NC14254 Color(Vizing定理)

题目链接 https://ac.nowcoder.com/acm/problem/14254

题目大意:给一个二分图(n<=1e3,m<=2e3),要求对它的边进行染色,相邻边(即有公共点的边)不能是同一种颜色,问最少用多少种颜色(k)能完成染色任务,并输出一组可行解(每条边的颜色为1~k间的数)。

在图论中有一个Vizing定理:二分图边着色所需最小颜色数,等于图中点的最大度数。我们设当前需要在u和v之间加一条边,设u点尚未用过的最小的颜色编号是x,v点尚未用过的最小颜色编号是y。那么如果x=y,就直接令边(u,v)的颜色是x(y)即可;如果x<y,我们依然令(u,v)的颜色是x,然后让点v原有的颜色为x的边变色为y,接下来对于这条边连接的点v',让它原有的颜色为y的边再变色为x……就这样一直修改下去,修改路径是一条从v出发,颜色依次是x、y、x……的边构成的路径(不会经过u)。
修改这条增广路的操作可以用dfs实现,复杂度是O(n)。在添加每条边的时候都有可能需要修改,所以整体复杂度O(mn)。

#include<bits/stdc++.h>
using namespace std;

const int maxn=1001;

int es[maxn][maxn];
int color[maxn<<1];
typedef pair<int,int> pir;
map<pir,int> mp;

void dfs(int u,int v,int x,int y){
    int to=es[v][x];
    //把uv边从y色染成x色
    es[u][x]=v;es[v][x]=u;
    if(!to){
        //如果v之前没有x色的边
        es[v][y]=0;
    }else{
        dfs(v,to,y,x);
    }
}

int main(){
    int n,m,cur[2];
    cin>>n>>m;
    int ans=0;
    for(int i=1,u,v;i<=m;i++){
        cin>>u>>v;
        mp[pir(u,v)]=i;
        mp[pir(v,u)]=i;
        cur[0]=cur[1]=1;
        while(es[u][cur[0]])
            cur[0]++;
        while(es[v][cur[1]])
            cur[1]++;
        if(cur[0]>cur[1]){
            swap(u,v);swap(cur[0],cur[1]);
        }
        ans=max(ans,cur[1]);
        if(cur[0]==cur[1]){
            es[u][cur[0]]=v;
            es[v][cur[0]]=u;
        }else{
            dfs(u,v,cur[0],cur[1]);
        }
    }
    cout<<ans<<endl;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=ans;j++){
            int v=es[i][j];
            if(v){
                color[mp[pir(i,v)]]=j;
            }
        }
    }
    for(int i=1;i<=m;i++)
        cout<<color[i]<<endl;
}

/*
5 4
1 2
1 3
1 4
4 5
*/
每日一题 文章被收录于专栏

暑期每日一题,尽量日更

全部评论

相关推荐

服从性笔试吗,发这么多笔,现在还在发。
蟑螂恶霸zZ:傻 x 公司,发两次笔试,两次部门匹配挂,
投递金山WPS等公司10个岗位 >
点赞 评论 收藏
分享
11-08 17:36
诺瓦科技_HR
点赞 评论 收藏
分享
牛客717484937号:双飞硕没实习挺要命的
点赞 评论 收藏
分享
2 收藏 评论
分享
牛客网
牛客企业服务