挺有意思的一道题。
首先如果没有环,那么一种颜色染完所有边,答案为 (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 ? '
' : ' ');
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 ? '
' : ' ');
return 0;
}
//