codeforces 1217D Coloring Edges 题解

挺有意思的一道题。

首先如果没有环,那么一种颜色染完所有边,答案为 \(1\)
这里我直接用拓扑排序判断有没有环了。

如果有环,一种颜色肯定是不行了。我们发现对于每一个环,可以视为从一个点出发,经过另一些点,再回到这个点的路径。
这里我们给每一个点任意赋予一个高度(就是赋予一个权值..吧),同时保证所有点高度不同,这时候我们发现从一个点 \(x\) 出发,走完第一步之后,要么是到达了高度比原来更高的点,要么到达了高度比原来更低的点,而最后我们要回到 \(x\),如果第一步往高处走了,环上总有至少一步需要往低处走,不然一定无法回到 \(x\)。另一种情况同理。

总而言之,每一个环必定同时包含走向更高高度的边和走向更低高度的边。

所以把高往低走的边染色为 \(1\),低往高走的染色为 \(2\)

然后这题就做完了。

高度怎么赋?随便怎么搞都可以,只要两两不同就行了。
这里我为了方便直接用了点的编号

代码:

// 头文件省略了
using namespace std;
typedef long long LL;

vector <LL> G[200005];
LL vis[200005],in[200005] = {0};
LL cnt = 0,n,m;

void tp_sort(){
	queue <LL> q;
	for(LL i = 1;i <= n;i ++){
		if(!in[i]){
			cnt --;
			q.push(i);
		}
	}
	while(!q.empty()){
		LL u = q.front(); q.pop();
		for(LL i = 0;i < G[u].size();i ++){
			LL v = G[u][i]; in[v] --;
			if(!in[v]){
				cnt --;
				q.push(v);
			}
		}
	}
} // 拓扑排序

LL u[200005],v[200005],col[200005];

int main(){
	cin >> n >> m;
	for(LL i = 1;i <= m;i ++){
		cin >> u[i] >> v[i];
		G[u[i]].push_back(v[i]); in[v[i]] ++;
	}
	cnt = n; tp_sort();
	if(!cnt){
		cout << 1 << endl;
		for(LL i = 1;i <= m;i ++) cout << 1 << (i == m ? '\n' : ' ');
		return 0; // 判断无环的情况
	}
	
	for(LL i = 1;i <= m;i ++){
		if(v[i] < u[i]) col[i] = 2;
		if(v[i] > u[i]) col[i] = 1;
	} // 有环,直接根据点编号大小关系给边染色
	cout << 2 << endl;
	for(LL i = 1;i <= m;i ++) cout << col[i] << (i == m ? '\n' : ' ');
	return 0;
}
//
posted @ 2020-04-21 14:09  ItzInstallB  阅读(119)  评论(0编辑  收藏  举报