CF 600F( 二分图

题目:给一个二分图,对每条边进行染色,求一种使得相邻边颜色都不同并且所用颜色最少的染色方案.

思路:颜色最少个数大于等于度最大的点的度数,然后要构造出一种染色方案.构造方法类似于二分匹配的搜索算法.对于每个点,记录与这个点相连的对应颜色的点,然后每次取最小的没有使用的颜色,如果颜色有冲突,对于两个点x,y,有cx没有在x的邻边出现,cy没有在y的邻边出现,把xy染成cx,然后冲突的边染色成cy,如果还有冲突,则用cx继续染色,由于是二分图没有奇环,所以必然可以最终找到替代方案.写法上有些技巧,参考了cf上红名巨巨的代码.

/*
* 没有过去,也没有未来
*/
#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <map>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <queue>
#include <stack>
#include <functional>
#include <set>
#include <cmath>
using namespace std;
#define IOS std::ios::sync_with_stdio (false);std::cin.tie(0)
#define pb push_back
#define PB pop_back
#define bk back()
#define fs first
#define se second
#define sq(x) (x)*(x)
#define eps (1e-10)
#define INF (0x3f3f3f3f)
#define clr(x) memset((x),0,sizeof (x))
#define cp(a,b) memcpy((a),(b),sizeof (b))

typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll,ll> P;

const int maxn=1005;
int linkx[maxn][maxn],linky[maxn][maxn];
int id[maxn][maxn];
int d[maxn*3];
int a,b,m;
int ans[maxn*maxn];
int main(){
   //freopen("/home/slyfc/CppFiles/in","r",stdin);
    //freopen("/home/slyfc/CppFiles/out","w",stdout);
    memset(linkx,-1,sizeof linkx);
    memset(linky,-1,sizeof linky);
    memset(id,-1,sizeof id);
    cin>>a>>b>>m;
    int maxd=0;
    for(int e=0;e<m;e++){
        int x,y;
        scanf("%d%d",&x,&y);
        d[x]++,d[y+a]++;
        maxd=max(maxd,d[x]);
        maxd=max(maxd,d[y+a]);
        id[x][y]=e;
        int cx=0,cy=0;
        while(linkx[x][cx]!=-1) cx++;
        while(linky[y][cy]!=-1) cy++;
        if(cx==cy){
            linkx[x][cx]=y;
            linky[y][cy]=x;
        }else{
            int left=x;
            int right=y;
            linkx[x][cx]=y;
            for(;;){
                int tmp=linky[right][cx];
                linky[right][cx]=left;
                linky[right][cy]=tmp;
                if(tmp==-1) break;
                int tmp0=linkx[tmp][cy];
                linkx[tmp][cy]=right;
                linkx[tmp][cx]=tmp0;
                if(tmp0==-1) break;
                left=tmp,right=tmp0;
            }
            
        }
    }
    cout<<maxd<<endl;
    for(int i=0;i<maxn;i++){
        for(int j=0;j<maxn;j++){
            if(linkx[i][j]!=-1){
                int y=linkx[i][j];
                ans[id[i][y]]=j+1;
            }
        }
    }
    for(int i=0;i<m;i++){
        printf("%d ",ans[i]);
    }
    return 0;    
}
View Code

 

转载于:https://www.cnblogs.com/Cw-trip/p/5010462.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值