ZOJ 1084 Channel Allocation 四色定理

本文探讨了一道AC率为42%的难题,利用四色定理解决地图着色问题,并通过两段代码示例展示了如何实现图着色算法。第一段代码使用递归深度优先搜索进行图着色,而第二段代码则采用贪心算法来分配最少的频道数。

这个题真难啊, AC率42%

这题用到了“四色定理” : 任何一张地图只用四种颜色就能使具有共同边界的国家着上不同的颜色。这里所指的相邻区域,是指有一整段边界是公共的。如果两个区域只相遇于一点或有限多点,就不叫相邻的。因为用相同的颜色给它们着色不会引起混淆。

我做了好几遍, 错了好几遍, 后来看了别人的代码, 勉强懂了, 但是还有挺多细节不懂,

我发现好多人发表的日志都差不多的代码,应该也看了别人的代码, 也不知道他们是否真的懂了。我把我理解的注释清楚点, 希望如果要是你看懂了, 能帮我解决疑问, 代码可以AC

#include "iostream"
#include "cstdio"
#include "cstring"
using namespace std;

int graph[30][30];
int used[30];
int n;

//此函数检验从node到结束, 在只有color中颜色下可否全填。
bool dfs(int node, int color){
	int i, j, flage;
	for(i = 0; i < color; i++){
		used[node] = i;				//给node涂色
	    flage = 1;
		for(j = 0; j < node; j++){		//对在node之前的节点进行检测
			if(graph[j][node] && used[j] == used[node]){		//如果节点j与node有关联,而且颜色相同, 可换种颜色
				flage = 0;
				break;
			}
		}
		if( flage && (node == (n - 1) || dfs(node+1, color))) return true;
		// 疑问2:上面这句也有点问题, 我把他改为:
		//	if( flage && node == (n - 1)) return true;
		// 然后这个for循环后 dfs(node+1, color); 不知道为什么不行
	}
	return false;
}

int main(){
	int i, j;
	while( cin >> n && n){
		char s[30];
		int flage = 0;					//判断是否超过一个节点相连, 如果相连那么1种肯定不行
		memset(graph, 0, sizeof(graph));

		for(i = 0; i < n; i++){
			scanf("%s", s);				//接收
			int len = strlen(s);
			if(len > 2){
				flage = 1;				//如果有一个s的长度大于2, 那么可能1个频道不行
			}
			for(j = 2; j < len; j++){
				graph[i][s[j] - 'A' ] = 1;	//构成graph数组
				graph[s[j] - 'A'][i] = 1;	// 疑问1: 我觉得这句话是多余的, 因为以后来时可以接收到
											//但是去掉这一句, 就不能Accepted
			}
		}
		if(!flage)							//flage还是为0, 那么可以用一个频道
			cout<< "1 channel needed."<<endl;
		else if (dfs(0, 2))					//从第0个节点给予2中颜色给予检测
			cout<< "2 channels needed."<<endl;
		else if (dfs(0, 3))
			cout<< "3 channels needed."<<endl;
		else								//有四色定理得,最多四种
			cout<< "4 channels needed."<<endl;
	}
	return 0;
}


下面在复制一个代码, 这段代码看似更简单

#include <stdio.h>
#include <string.h>
int graph[26][26];
int main()
{
// freopen("in.txt","r",stdin);
 int n,i,j,len,max,d[27],channel[26];//channel[]存放各个发射器使用的频道编号
 char s[50];
 while(scanf("%d",&n)&&n)
 {
  memset(graph,0,sizeof(graph));
  memset(channel,0,sizeof(channel));
  for(i=0;i<n;i++)   //建立有向图
  {
   scanf("%s",s);
   len=strlen(s);
   for(j=2;j<len;j++)
    graph[i][s[j]-'A']=1;
  }
  max=0;
  for(i=0;i<n;i++)
  {
   memset(d,0,sizeof(d));
   for(j=0;j<i;j++)  //寻找有冲突的频道编号
    if(graph[i][j])
     d[channel[j]]=1;//d[k]==1表示k频道有冲突
   for(j=1;;j++)   //寻找可以使用的编号最小的频道
    if(d[j]==0)
     break;
   channel[i]=j;
   if(j>max)
    max=j;   
  }
  if(max==1)
   printf("1 channel needed.\n");
  else
   printf("%d channels needed.\n",max);
 }
 return 0;
}

第二段代码来自 轩辕剑云中界的博客


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值