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
*/
每日一题 文章被收录于专栏

暑期每日一题,尽量日更

全部评论

相关推荐

最近和朋友聊天,她说了句让我震惊的话:"我发现我连周末点外卖都开始'最优解'了,一定要赶在高峰期前下单,不然就觉得自己亏了。"这不就是典型的"班味入侵"吗?工作思维已经渗透到生活的方方面面。
小型域名服务器:啊?我一直都这样啊?我还以为是我爱贪小便宜呢?每次去实验室都得接一杯免费的开水回去,出门都得规划一下最短路径,在宿舍就吃南边的食堂,在实验室就吃北边的食堂,快递只有顺路的时候才取。
点赞 评论 收藏
分享
10-11 17:45
门头沟学院 Java
走吗:别怕 我以前也是这么认为 虽然一面就挂 但是颇有收获!
点赞 评论 收藏
分享
2 收藏 评论
分享
牛客网
牛客企业服务