Misra & Gries边着色算法

Misra & Gries边着色算法

边着色问题:给图的每条边制定一种颜色,使得任意两条相邻的边的颜色均不相同

为了解决本次的问题首先需要引入:Misra & Gries边着色算法

Misra & Gries边着色算法是图论算法的一种,能够在多项式内找到任意图的一种边着色方案。这种着色算法最多使用 Δ + 1 \Delta+1 Δ+1种颜色, Δ \Delta Δ是该图节点的最大度数。这对于一些图而言是最优的,根据Vizing定理,最坏情况下,这种算法给出的结果比最优值多使用一种颜色

论文: “A constructive proof of Vizing’s theorem”

首先介绍几个概念:

介绍扇之前需要先引入定义.对于一种颜色x,如果 c o l o r ( u , z ) ≠ x color(u,z)\ne x color(u,z)̸=x对所有的 ( u , z ) ∈ E ( G ) ( z ≠ v ) (u,z)\in E(G)(z\ne v) (u,z)E(G)(z̸=v)成立,则称这种颜色x对边(u,v)未使用

再来引入扇的定义.

对顶点u的一扇,是一个顶点序列,记为 F [ 1 : K ] F[1:K] F[1:K]该序列满足:

  1. F[1:k]为一个包含u的所有或者部分邻接节点的序列
  2. ( F [ 1 ] , u ) (F[1],u) (F[1],u)未被着色
  3. c o l o r ( u , F [ i + 1 ] ) ​ color(u,F[i+1])​ color(u,F[i+1])对于 ( F [ i ] , u ) ​ (F[i],u)​ (F[i],u)未使用

给定一个扇F,任意边 ( F [ i ] , x ) (F[i],x) (F[i],x) ( 1 ≤ i ≤ k ) (1\le i\le k) (1ik)是扇的一条边.现在令两个颜色c与d,则一个 c d x cd_x cdx路径定义为经过节点x,由只含c,d颜色的边组成的最大路径(即不能再添加更多的边)

扇的旋转

对于一个给定的节点x的一个扇F[1:k],旋转即是进行:

  1. color(F[i],x)=color(F[i+1],x)
  2. 除去边 ( F [ k ] , x ) (F[k],x) (F[k],x)的颜色

由于前面提到的扇子的性质( c o l o r ( u , F [ i + 1 ] ) color(u,F[i+1]) color(u,F[i+1])对于 ( F [ i ] , u ) (F[i],u) (F[i],u)未使用)因此旋转后,其染色依然是满足条件的

路径的翻转

前面提到的路径 c d x cd_x cdx,对其进行翻转即是将路径上所有的颜色为c的边的颜色改为颜色d,所有颜色为d的边的颜色改为c.如果x是路径末端的点.则这一操作会将使得点x多释放出一种颜色.因为这一操作对于边上点,翻转操作只是交换了边的颜色,而未增加新的颜色,因此其并不会改变染色的有效性.而对于在端点上的x其原本只有c或者d中的一种,暂且假设为d,在翻转之后其就变成了c,那么d这一颜色就空了出来.就对于x增加了一种颜色

算法实现

有了扇的定义之后就可以描述这一算法了:

输入:图G

输出:对图G的一个合适的染色方案

U : = E ( G ) U:=E(G) U:=E(G)

while |U|!=0 do
	令(u,v)为集合U中的任意一条边
	令F[1:k]为u的一个最大扇,且F[1]=v
	令c为对于u未使用的一种颜色,d为对于F[k]的一种颜色
	翻转cdu
	令w为扇F中的一个点,令一个新的扇其为F'[F[1]...w]是一个扇,且颜色d对于w未使用
	旋转扇F'再将已然无色的(u,w)=d
	U:=U-{(u,v)}
end while

Game Scheduling

题目大意

有m支队伍,每支队伍有n个选手,让所有的选手和其他组的选手进行一次较量.问怎么安排可以让所有的选手在一轮中只出现一次.且最多一轮不出现.

解题思路

可以将这个问题转换成上面介绍的边染色问题.将两个选手在哪一出战转化成选手之间连边建图,对图进行染色并得到结果.由于Misra&Gries边着色算法具有可以得到最少着色的特点(具体为什么这就是最少的着色不再赘述,可以看论文了解),因此,直接由此算法得出染色方案即是答案.

AC代码

#include<bits/stdc++.h>
using namespace std;
typedef  pair<int,int> pii;
const int sz=26*26;
int match[sz][sz];
bool vis[sz];
bool col[sz]; 
int n,m;
int get_block(int x)
{
	memset(col,0,sizeof(col));
	for(int i=0;i<n*m;i++) col[match[x][i]]=1;
	for(int i=1;i<n*m;i++) if(!col[i]) return i;
	return n*m;
}
int check_conflict(int x,int loc)
{
	for(int i=0;i<n*m;i++) if(match[x][i]==loc) return i;
	return n*m;
}
void recol(int x, int y)
{
	int pre_match=get_block(y);
	int conflict=check_conflict(x,pre_match);
	memset(vis,0,sizeof(vis));
	vis[y] = 1;
	vector<pii> match_line;
	match_line.push_back(pii(y,pre_match));
	while (conflict!=n*m && !vis[conflict]) {
		vis[conflict] = 1;
		y=conflict;
		pre_match = get_block(y);
		match_line.push_back(pii(y,pre_match));
		conflict = check_conflict(x, pre_match);
	}
	if (conflict==n*m) {
		for(auto t:match_line) {
			match[x][t.first] = t.second;
			match[t.first][x] = t.second;
		}
	} else {
		int pre_match_x = get_block(x);
		int conflict_x=check_conflict(conflict,pre_match_x);
		match[x][conflict] = pre_match_x;
		match[conflict][x] = pre_match_x;
		while (conflict_x!=n*m) {
			int temp= check_conflict(conflict_x,pre_match);
			match[conflict][conflict_x] = pre_match;
			match[conflict_x][conflict] = pre_match;
			conflict=conflict_x;
			conflict_x=temp;
			swap(pre_match_x,pre_match);
		}
		recol(x,match_line[0].first);
	}
}
int main()
{
 	scanf("%d%d",&n,&m);
	for(int i=0;i<n*m;i++)
	{
		for(int j=0;j<n*m;j++)
		{
			if(i/n!=j/n&&!match[i][j])
				recol(i,j);
		}
	}
	int tot=n*(m-1)*n*m/2;
	for(int k=1;tot;k++)
	{
		for(int i=0;i<n*m;i++)
		{
			for(int j=i+1;j<n*m;j++)
			{
				if(match[i][j]==k)
				{
					tot--;
					printf("%c%d-%c%d ",'A'+i/n,i%n+1,'A'+j/n,j%n+1);
				}
			}
		}
		cout<<endl;
	}
}
  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值