• CF1240F Football


    题目传送门

    分析:
    先转化一下模型,把队伍看作点,两个队伍比赛看作边,给边(K)染色,假设以点(i)为端点,颜色最大的值为(mx_i),最小为(mn_i)
    我们需要找到染色方案使得对于每一个点(i)(mx_i-mn_ileq 2)
    不知道所有的比赛是否都可以举行,我们先尝试看看能不能每条边都染色
    先思考(K=2)的情况吧,我们新建节点0,如果一个点度数为奇数,将这个点与0连边
    接下来这个图的每个点度数都为偶数了
    接下来在这个图上胡乱dfs,保证所有边只经过一次,把这些边按顺序加入队列
    把这些边按加入顺序的奇偶性染色,再删去0和与0相连的边
    可以保证每个点(mx_i-mn_ileq 1)
    非常巧妙的构造,可以联系一下欧拉回路证明其正确性
    访问一个点再离开,入边和出边在队列里相邻,必定不同色,可以被抵消二保证(mx_i-mn_i=0)
    删除0点后度数为奇数的点最多被删一条边,也能保证(mx_i-mn_i=1)
    对于(K>2)的情况,我们先随机染色,然后找到某个不合法的点出现最多的颜色(C_1),和最少的颜色(C_2)
    (C_1,C_2)(K=2)的方法染色,这样我们会让(mx_i-mn_i)不断缩小,最后求得答案
    这样可以求得让每一条边都染色的合法方案,即每一场比赛都能举行
    (不会证明QAQ,感性理解感觉很对2333)
    最坏情况复杂度(O(nm^2)),由于随机跑不满,可以通过(
    (可能是我的写太丑了常数巨大,随机种子多试了几次才过的

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<algorithm>
    #include<queue>
    #include<bitset>
    #include<map>
    #include<set>
    
    #define maxn 1105
    #define MOD 1000000007
    
    using namespace std;
    
    inline int getint()
    {
    	int num=0,flag=1;char c;
    	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
    	return num*flag;
    }
    
    int n,m,K;
    struct node{
    	int u,v,col;
    }E[maxn];
    int D[105][maxn],d[105];
    int C1=1,C2=1;
    vector<int>G[105],Id[105];
    int vis[maxn],stk[maxn],tp;
    
    inline bool check()
    {
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=1;j<=K;j++)
    		{
    			if(D[i][j]>D[i][C1])C1=j;
    			if(D[i][j]<D[i][C2])C2=j;
    		}
    		if(D[i][C1]-D[i][C2]>2)return 0;
    	}
    	return 1;
    }
    
    inline void dfs(int u)
    {
    	for(int i=0;i<G[u].size();i++)if(!vis[Id[u][i]])
    	{
    		vis[Id[u][i]]=1,stk[++tp]=Id[u][i];
    		dfs(G[u][i]);
    	}
    }
    
    int main()
    {
    	srand(19260817);
    	n=getint(),m=getint(),K=getint();
    	for(int i=1;i<=n;i++)getint();
    	for(int i=1;i<=m;i++)E[i].u=getint(),E[i].v=getint(),E[i].col=rand()%K+1;
    	for(int i=1;i<=m;i++)D[E[i].u][E[i].col]++,D[E[i].v][E[i].col]++;
    	while(1)
    	{
    		if(check())break;
    		for(int i=1;i<=m;i++)if(E[i].col==C1||E[i].col==C2)
    		{
    			G[E[i].u].push_back(E[i].v),G[E[i].v].push_back(E[i].u);
    			Id[E[i].u].push_back(i),Id[E[i].v].push_back(i);
    			d[E[i].u]++,d[E[i].v]++;
    		}
    		int num=m;
    		for(int i=1;i<=n;i++)if(d[i]&1)
    		{
    			G[i].push_back(0),G[0].push_back(i);
    			Id[i].push_back(++num),Id[0].push_back(num);
    		}
    		for(int i=0;i<=n;i++)dfs(i);
    		for(int i=1;i<=n;i++)D[i][C1]=D[i][C2]=0;
    		while(tp)
    		{
    			if(stk[tp]<=m)E[stk[tp]].col=tp&1?C1:C2,D[E[stk[tp]].u][E[stk[tp]].col]++,D[E[stk[tp]].v][E[stk[tp]].col]++;
    			tp--;
    		}
    		for(int i=0;i<=n;i++)G[i].clear(),Id[i].clear();
    		memset(d,0,sizeof d),memset(vis,0,sizeof vis);
    	}
    	for(int i=1;i<=m;i++)printf("%d
    ",E[i].col);
    }
    

  • 相关阅读:
    .Net4.0并行库介绍——线程专有存储
    解决WPF中TextBox文件拖放问题
    POJ 2063 Investment(完全背包)
    HDU 1698 Just a Hook(线段树,成段更新)
    HDU 2665 Kth number(划分树入门题,纯套模板)
    HDU 4251 The Famous ICPC Team Again(划分树入门题)
    POJ 3295 Tautology(构造法)
    HDU 1540 Tunnel Warfare(线段树,去最大连续区间)
    HDU 1394 Minimum Inversion Number(求逆序数,线段树或者树状数组)
    POJ 2993 Emag eht htiw Em Pleh(水模拟)
  • 原文地址:https://www.cnblogs.com/Darknesses/p/13280860.html
Copyright © 2020-2023  润新知