璟雯院

珺璟如晔,雯华若锦

用户工具

站点工具


icpc:problems:usaco22jan_cereal_2_s
problems
名称Cereal 2 S
题目编号USACO22JAN_S3
题目链接luogu.com.cn/…
来源USACO
算法分类基环树, 图论
难易程度小有难度

Cereal 2 S

想法

将牛作为边,草作为点进行建无向图。有冲突的牛形成了一个联通块,现考虑单独的一个联通块。另这个联通块点为n,边为m。

  1. n > m : 这个情况不存在,因为一头牛会连接两个点,对于一个联通块来说不会存在不连接边的情况。
  2. n - 1 == m : 该图形成了一棵树,必定可以给每条边分配一个点。
  3. n == m : 该图形成了一棵基环树,必定可以给每条边分配一个点,对于序列来说需要先从环上取边。
  4. 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 由 温婕莺