链接:http://poj.org/problem?id=1129
题意:有一堆相互连边的(整个图不一定连通)的Speaker网络,每个Speaker需要channel进行工作,但是要求相邻的Speaker之间不能使用相同的channel。
图的着色问题,学习了。
注:这个题用暴力枚举在poj能AC,但是有些情形下这种方法的结果是不对的。用搜索能正确的给出结果,但是搜索poj过不了(估计这是评测的问题吧。)
贴代码。
//图的着色问题
//暴力枚举
//虽然过了,但是不能解决下面这组样例
/*
4
A:D
B:C
C:BD
D:AC
上面这组样例结果不正确,但是下面这组结果正确。
两组数据图的结构一样,但是是标号的顺序不一样
44
A:B
B:AC
C:BD
D:C
估计是因为,A、B、C、D不是顺着来的
所以这道题用搜索能正确解决(不过我找的正确的搜索代码提交之后却是WA,评测有问题)
*/
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#define MAX 27
#define MAXS 30
using namespace std;
int n,map[MAX][MAX],corlor[MAX],vist[MAX];
char s[MAXS];
int main()
{
while(scanf("%d",&n)!=EOF)
{
if(!n)return 0;
memset(map,0,sizeof(map));
memset(corlor,0,sizeof(corlor));
int maxcorlor=0;//所需要的最多的频道(颜色)个数
for(int i=0;i<n;i++)
{
scanf("%s",s);
int len=strlen(s);
for(int j=2;j<len;j++)
map[s[0]-'A'][s[j]-'A']=1;
}
for(int i=0;i<n;i++)//枚举每个顶点
{
corlor[i]=n+1; //初始化每个点最开始的颜色为最大(即使用最多颜色种类)
memset(vist,0,sizeof(vist));//vist[i]=1,表示第i种颜色呗使用;初始化各种颜色都未被使用
for(int j=0;j<n;j++)
{
if(map[i][j]&&corlor[j])//corlor[j]存储了点j的颜色,直接找与点i相邻的节点
vist[corlor[j]]=1; //表示该颜色被使用
}
for(int k=1;k<=n;k++)
{
if(!vist[k]&&corlor[i]>k)
{
corlor[i]=k;
break;
}
}
if(maxcorlor<corlor[i])
maxcorlor=corlor[i];
}
/*for(int i=0;i<n;i++)
printf("%c %d\n",i+'A',corlor[i]);*/
if(maxcorlor==1)printf("1 channel needed.\n");
else printf("%d channels needed.\n",maxcorlor);
}
return 0;
}
/*这是我在网上找的一个搜索的代码,下面所说的通道即为上面说的颜色*/
/*这个搜索代码个人觉得还是很棒的!*/
#include <iostream>
using namespace std;
char str[30];
bool map[30][30];
int chan[30];//记录第i个结点使用的颜色(相当于上面的corlor[])
int n,res;
bool isLeagal( int nth, int id )
{
for ( int i = 1; i < nth; i++ ) //若repeater i 与repeater nth 有关联且通道id已经被使用,则不可行。
if ( map[i][nth] && chan[i] == id ) //i<nth,i的标号小于当前那个最大节点的编号,因为nth是逐一递归下来的
return false; //所以,只要比较比nth小的结点就可以了,比nth大的,肯定还没有使用过通道
return true;
}
void dfs( int nth, int mini ) // mini带代表了通道的个数,编号1,2,3,4... 若通道N被使用,则说明至少需要N个通道。
{
if ( nth > n )
{
if ( mini < res )
{
res = mini;
/*for(int i=1;i<=n;i++)
printf("%c %d\n",'A'+i-1,chan[i]);
*/
return;
}
}
for ( int i = 1; i <= mini; i++ )//这里i表颜色(通道)
{
if ( isLeagal(nth,i) ) // 不增加通道个数,即在编号1...mini的通道中为第nth个repeater选择通道
{
chan[nth] = i;
dfs(nth+1,mini);
}
}
chan[nth] = mini+1; // 选择第nth个repeater的通道为编号mini+1的通道
dfs(nth+1,mini+1);
}
int main()
{
while ( cin >> n && n )
{
memset(map,0,sizeof(map));
memset(chan,0,sizeof(chan));
for ( int i = 1; i <= n; i++ )
{
cin >> str;
int len=strlen(str);
for ( int j = 2; j < len; j++ )
map[str[0]-'A'+1][str[j]-'A'+1] = map[str[j]-'A'+1][str[0]-'A'+1] = true;
}/*建图*/
res = 30;
dfs(1,0);
if ( res == 1 )
cout << res << " channel needed." << endl;
else
cout << res << " channels needed." << endl;
}
return 0;
}