icpc:problems:usaco22jan_cereal_2_s
目录
problems | |
---|---|
名称 | Cereal 2 S |
题目编号 | USACO22JAN_S3 |
题目链接 | luogu.com.cn/… |
来源 | USACO |
算法分类 | 基环树, 图论 |
难易程度 | 小有难度 |
Cereal 2 S
想法
将牛作为边,草作为点进行建无向图。有冲突的牛形成了一个联通块,现考虑单独的一个联通块。另这个联通块点为n,边为m。
- n > m : 这个情况不存在,因为一头牛会连接两个点,对于一个联通块来说不会存在不连接边的情况。
- n - 1 == m : 该图形成了一棵树,必定可以给每条边分配一个点。
- n == m : 该图形成了一棵基环树,必定可以给每条边分配一个点,对于序列来说需要先从环上取边。
- n < m : 会存在边分配不到点的情况,但是每个点都会有一个分配到的边。被取出来的边形成一个图,该图一定是一个基环树。故此问题转换为从一个图中取一个基环树。对于序列来说需要先从环上取边。
所以,对于任意一个联通块,先在此联通块中寻找环,找到环后先从环上取边,接下来就直接可以进行深度优先扩展,一定取出来的为一棵基环树。
代码实现
#include<cstdio> #include<cstring> using namespace std; const int N = 1e5+10; struct node{ int v, next, pos; bool is_first; }; node edge[2*N]; int head[N], ans[N]; int n, m, ans_cnt, cnt=-1, _first, ig_edge; bool vis[N], this_vis[N], vis_cow[N]; void add_edge(int x, int y, int pos, bool f) { edge[++cnt].v = y; edge[cnt].next = head[x]; edge[cnt].pos = pos; edge[cnt].is_first = f; head[x] = cnt; return ; } void find_cycle(int x, int pre = -1) { for(int i=head[x]; ~i && (_first == -1); i = edge[i].next) { int v = edge[i].v; if(i == (pre^1) && pre != -1) continue; if(this_vis[v]) { if(edge[i].is_first) { _first = x; ig_edge = i; } else { _first = v; ig_edge = i^1; } return ; } else { this_vis[v] = true; find_cycle(v, i); } } return ; } void DFS(int x) { vis[x] = true; for(int i=head[x]; ~i; i=edge[i].next) { int v = edge[i].v; if(vis[v] || i == ig_edge )continue; ans[++ans_cnt] = edge[i].pos; vis_cow[edge[i].pos] = true; DFS(v); } return ; } int main() { memset(head, -1, sizeof(head)); scanf("%d %d", &n, &m); for(int i=1; i<=n; i++) { int f, s; scanf("%d %d", &f, &s); add_edge(f, s, i, true); add_edge(s, f, i, false); } for(int i=1; i<=m; i++) { if(vis[i]) continue; memset(this_vis, false, sizeof(this_vis)); _first = -1; ig_edge = -1; this_vis[i] = true; find_cycle(i); if(_first == -1) { DFS(i); } else { ans[++ans_cnt] = edge[ig_edge].pos; vis_cow[edge[ig_edge].pos] = true; DFS(_first); } } int c = 0; for(int i=1; i<=n; i++) if(!vis_cow[i]) { c++; ans[++ans_cnt] = i; } printf("%d\n", c); for(int i=1; i<=n; i++) printf("%d\n", ans[i]); return 0; }
/app/www/public/data/pages/icpc/problems/usaco22jan_cereal_2_s.txt · 最后更改: 2023/06/03 11:52 由 温婕莺