CF1240F Football 题解
题意
(稍微简化了一些)
\(n\) 个点, \(m\) 条边,每条边需要染成 \(k\) 种颜色中的一种,要求对于每个点,与其相连的边中任意两种颜色数量不超过 \(2\) ,构造方案。
\((1\le n\le100,1\le m,k\le1000)\)
题解
这题太牛逼了!!!
莫名想到把这个图变成二分图,把边 \(u,v\) 变成 \((u,v+n)\) 即可。
如果能保证此时每个点的颜色差不超过 \(1\) ,就能满足题意。(真可以满足……)
颜色差不超过 \(1\) ,先设这个点的度数为 \(d\) ,设 \(d=ak+b\) ,所以能有 \(a\) 组有 \(k\) 种颜色互不相同,另外一组有 \(b\) 个不同的颜色。
把每组变成一个点,只要保证之前的点颜色满了,现在的尽量满即可。
考虑新加一条边的时候,连边 \((u,v)\) 。(刚才提到的点)
现在要对于一个点,没有两条边颜色相同了。
首先如果 \(u\) 和 \(v\) 有同一个颜色没有被使用过,就直接将这个边弄上这个颜色。
如果没有,随便对 \(u\) 找一个没用的颜色 \(c1\) ,对 \(v\) 找一个没用过的颜色 \(c2\) 。
首先把 \(v\) 占用了颜色 \(c1\) 的边颜色变成 \(c2\) ,最先的这条边颜色为 \(c1\) 。
此时颜色为 \(c2\) 指向的点肯定没有被占用过 \(c1\) ,把原本颜色是 \(c2\) 的边变成 \(c1\) 即可。
这样递归下去,直到没有冲突为止。
考虑是否有无法匹配的问题,即又走回 \(u\) ,此时是一个偶环,则边颜色为 \(c2\) ,说明 \(u\) 没有 \(c2\) 这条边,矛盾。
所以这样匹配就行了。
复杂度大概分析一下是 \(O(nm^2)\) 。但完全跑不满。
代码:
#include <bits/stdc++.h>
using namespace std;
const int N=2005;
int n,m,k,tot,d[N],pn[N],co[N],id[N][N],to[N][N];
void upd(int x,int c1,int c2){
swap(id[x][c1],id[x][c2]);swap(to[x][c1],to[x][c2]);
co[id[x][c2]]=c2;
if(to[x][c2]) upd(to[x][c2],c2,c1);
}
signed main(){
scanf("%d%d%d",&n,&m,&k);
for(int i=1,x;i<=n;i++) scanf("%d",&x);
for(int i=1,u,v;i<=m;i++){
scanf("%d%d",&u,&v);v+=n;
if(d[u]%k==0) pn[u]=++tot;
if(d[v]%k==0) pn[v]=++tot;
d[u]++;d[v]++;u=pn[u];v=pn[v];
int&c=co[i];
for(int j=1;j<=k;j++)
if(!to[u][j]&&!to[v][j]) {c=j;break;}
if(!c){
int cc;
for(int j=1;j<=k;j++)
if(!to[u][j]) {c=j;break;}
for(int j=1;j<=k;j++)
if(!to[v][j]) {cc=j;break;}
upd(v,c,cc);
}
to[u][c]=v;to[v][c]=u;id[u][c]=id[v][c]=i;
}
for(int i=1;i<=m;i++) printf("%d\n",co[i]);
return 0;
}

浙公网安备 33010602011771号