codefroces 1217 D. Coloring Edges(拓扑排序)

传送门

题意:

给出一个有向图,给每条边染色,如果图中存在环,那么这个环的每条边不能是同一种颜色。求染色需要的最少颜色数量。

题解:

可以分为两种情况讨论:

\(1.\) 图中无环,那么每条边都可以染成同一种颜色。

\(2.\)​ 图中有环,那么只需两种颜色即可。为什么?我们可以先找出图中所有的最小的环,即不被其他环包含的环。

对于这些环,两两之间是相互独立的,那么每个环都可以只染1,2两种颜色,对于包含其他环的环,由于小的环已经满足条件了,所以大的环自然也满足条件了。

再考虑怎么染色,既然知道只需染1,2两种颜色,那么我们可以这样构造:节点编号小的连向编号大的边,染成1,反之,染成2。因为对于一个环,一定存在节点编号小的连向编号大的边和节点编号大的连向编号小的边,因此满足条件。

代码:

#pragma GCC diagnostic error "-std=c++11"
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#include<ctime>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int MAXN=2e5+5;
const int inf=0x3f3f3f3f;
vector<int> g[MAXN];
int in[MAXN];
int n,m;
int u[MAXN], v[MAXN];
bool top()
{
    int cnt = 0;
    queue<int> q;
    for (int i = 1; i <= n;i++){
        if(!in[i])
            q.push(i),cnt++;
        }
    while(!q.empty())
    {
        int now = q.front();
        q.pop();
        in[now]--;
        for(auto i:g[now])
        {
            in[i]--;
            if(!in[i])
                q.push(i), cnt++;
        }
    }
    if(cnt==n)
        return true;
    else
        return false;
}
int main()
{
    cin >> n >> m;
    for (int i = 1; i <= m;i++){
        //int u, v;
        cin >> u[i] >> v[i];
        g[u[i]].push_back(v[i]);
        in[v[i]]++;
    }
    if(top())
    {
        cout << 1 << endl;
        for (int i = 1; i <= m;i++){
            cout << 1 << " ";
        }
    }
    else 
    {
        cout << 2 << endl;
        for (int i = 1; i <= m;i++){
            if(u[i]<v[i])
                cout << 1 << " ";
            else
                cout << 2 << " ";
        }
    }
}
posted @ 2021-08-23 10:59  TheBestQAQ  阅读(48)  评论(0)    收藏  举报