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;
}
posted @ 2021-09-02 16:41  shrtcl  阅读(92)  评论(0)    收藏  举报