POJ1129 Channel Allocation(AC)

Channel Allocation
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 13434 Accepted: 6876

Description

When a radio station is broadcasting over a very large area, repeaters are used to retransmit the signal so that every receiver has a strong signal. However, the channels used by each repeater must be carefully chosen so that nearby repeaters do not interfere with one another. This condition is satisfied if adjacent repeaters use different channels.

Since the radio frequency spectrum is a precious resource, the number of channels required by a given network of repeaters should be minimised. You have to write a program that reads in a description of a repeater network and determines the minimum number of channels required.

Input

The input consists of a number of maps of repeater networks. Each map begins with a line containing the number of repeaters. This is between 1 and 26, and the repeaters are referred to by consecutive upper-case letters of the alphabet starting with A. For example, ten repeaters would have the names A,B,C,...,I and J. A network with zero repeaters indicates the end of input.

Following the number of repeaters is a list of adjacency relationships. Each line has the form:

A:BCDH

which indicates that the repeaters B, C, D and H are adjacent to the repeater A. The first line describes those adjacent to repeater A, the second those adjacent to B, and so on for all of the repeaters. If a repeater is not adjacent to any other, its line has the form

A:

The repeaters are listed in alphabetical order.

Note that the adjacency is a symmetric relationship; if A is adjacent to B, then B is necessarily adjacent to A. Also, since the repeaters lie in a plane, the graph formed by connecting adjacent repeaters does not have any line segments that cross. 

Output

For each map (except the final one with no repeaters), print a line containing the minumum number of channels needed so that no adjacent channels interfere. The sample output shows the format of this line. Take care that channels is in the singular form when only one channel is required.

Sample Input

2
A:
B:
4
A:BC
B:ACD
C:ABD
D:BC
4
A:BCD
B:ACD
C:ABD
D:ABC
0

Sample Output

1 channel needed.
3 channels needed.
4 channels needed.

 

一组很牛的数据

6

A:BEF

B:AC

C:BD

D:CEF

E:ADF

F:ADE

out

3 channels needed.

即:A(1)B(2)C(3)D(1)E(2)F(3)

 

//还是要把所有的情况都枚举出来,然后得到最小值,最小值一般都这样的

 

 

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

#if 1

#define MAXINT 100
#define MAXCITY 30 //题中说一共26个点

//第一次提交WA,自己做的是第一点置1,然后和他相邻的都+1,这样不对的,其实和他相邻的都可以是2不用递增的
//修改之后还是WA,我的做法是求不到最优解,还是不行,而且自己的做法不是dfs,感觉像是在模拟一样,不是dfs
//看了小优博客的做法,明白了我的思考方法冒似是不对的,我是A:BCD,A确定了,直接就确定BCD,然后后面再修改,
//这样好像得到的不是最优解,小优是一个一个取的比如A:BCD我只会订A的频道数,其它都不订,保证和后面相邻的不重复就可以,但是小优的做法也不对,这样得不到最优解的,顺序取也不对
//小优的顺序着色也是错的。。。
//这个是做的对的http://www.cnblogs.com/wally/p/3295370.html,网上有很多错误的答案,上面那个牛数据就过不了,还是得遍历所有的这个也不对的,会有重复
//最终还是使用了回溯

char str[MAXINT];
int adjacen[MAXCITY][MAXCITY];//是否相邻
int adnum[MAXCITY];//每个接收器相邻点的个数
int visit[MAXCITY];//第n个频道是否已经分配
int chanel[MAXCITY];//接收器配置的频道数
int visistchanel[MAXCITY][MAXCITY]; //visistchanel[0][1] 和0相邻的接收器中第1个channel已经分配
int ans = 4; 
int R = 0;
int tusenum = 0;

//我原来的理解是用并查集,如果都是各位一个,那就只需要1个,如果有多少个公用1个祖先,那就要各取一个,结果就是同个祖先数中的成员数
//题目是相邻的不能用1个频道,如果自己用并查集来做的话,可能不想邻的也会让我归到一个范围里去了,是不是就有问题,这道题搜了下都不是用
//并查集做的,都是用DFS,用染色定理做的
//并查集是找大家在一个连通分支的,这个应该不能一概认为是在一个集合中的,ab相邻,bc相邻,但是不能认为ac相邻,如果用并查集的话,就会认为他们是一个集合,那可能就不对了

void init()
{
	int i = 0;
	int j = 0;
	for (i = 0; i < MAXINT;i++)
	{
		str[i] = '\0';
	}

	for (i = 0; i < MAXCITY; i++)
	{
		for (j = 0; j < MAXCITY; j++)
		{
			adjacen[i][j] = 0;
			visistchanel[i][j] = 0;
		}
		adnum[i] = 0;
		visit[i] = 0;
		chanel[i] = 0;
	}

	ans = 4;
	tusenum = 0;
	return;
}


int strlen()
{
	int size = 0;
	while ('\0'!= str[size])
	{
		size++;
	}
	return size;
}

void parseit()
{
	int size = 0;
	int start = 0;
	int i = 0;
	size = strlen();
	start = str[0]-'A'+1;//第一个是开始
	if (size >= 2) //如果是A:就不用进这个循环了
	{
		for (i = 2; i < size; i++)
		{
			if ('\0' != str[i])
			{
				adjacen[start][str[i]-'A'+1] = 1; //这样从1开始
				adnum[start]++;
			}
		}
	}

	return;
}

#if 0 //自己原来的做法,A:BCD,确定了A,直接就确定后面的三个,这样是得不到最优解的
void dfs()
{
	int i = 0;
	int j = 0;
	int k = 0;
	int city = 0;
	int tmechannel = 1;	

	//一个一个找接收点的频道,是否可以
	for (j = 0; j < R;j++)
	{
		city = 0;
		for (i = 0; i < R; i++)
		{
			tmechannel = 1; //置成0
			if (0 == adjacen[j][i]) continue;//不相邻不考虑
			if ((1 == visit[i]) && (chanel[j] != chanel[i])) //不能一样,如果一样要进行修改的
			{
				city += 1;
				if (i != j)
				{
					visistchanel[j][chanel[i]] = 1;  //j相邻的接收器中已经有分配channel[i]所代表的channel的
				}
				continue;//如果第i个接收器已经分配channel就不考虑再分配了
			}
			//每个都可以从1开始试起
			//while ((tmechannel == chanel[j]) && (tmechannel == chanel[i]))
			//求A:BC中的A
			if (i == j)
			{
				if (0 == visit[j])  //没赋值过
				{
					while (1 == visistchanel[j][tmechannel])
					{
						tmechannel += 1;
					}
				}
				else
				{
					tmechannel = chanel[i];
				}
			}	
			else
			{
				while (((tmechannel == chanel[j]) && (0 == visit[i])) || ((1 == visit[i]) && (chanel[i] == chanel[j])) || (1 == visistchanel[i][tmechannel]))
				{
					chanel[i] = tmechannel + 1;		
					tmechannel += 1;
				}
			}
			
			chanel[i] = tmechannel;
			if (i != j)
			{
				visistchanel[j][tmechannel] = 1; //知道A:BC 类似于A知道相邻的哪些被占用了
				visistchanel[i][chanel[j]] = 1;  //知道A:BC 类似于B知道A哪个被占用了
			}
			
			visit[i]  = 1;
			city += 1;

			if (ans < tmechannel) ans = tmechannel;

			if ((adnum[j]+1) == city)  //+1是因为还有A:BC 这个A本身
			{
				break;
			}
		}
	}

	return;
}

#endif

void initvist()
{
	int j = 0;
	for (j = 0; j < MAXCITY; j++)
	{
		visit[j] = 0;
	}
	return;
}

#if 0  //顺序着色也不对的。。。
void baosou()
{
	int i = 0;
	int j = 0;
	int city = 0;
	for (i = 0; i < R;i++)
	{
		initvist();
		city = 0;
		//每个i循环只会定i的频道数
		//j循环是看和i相邻的频道是否分配,然后来决定i的频道数是多少
		for (j = 0; j <= R;j++)
		{
			if (0 == adjacen[i][j]) continue;//不相邻不考虑
			//说明第j个接收器已经分配频道
			if (0 != chanel[j])
			{
				visit[chanel[j]] = 1;				
			}
			city += 1;
			if (adnum[i] == city)
			{
				break;
			}
		}

		//给顶点i设频道数
		for (j = 1; j <= R; j++)
		{
			if (!visit[j])
			{
				chanel[i] = j;
				break;
			}
		}
		if (ans < chanel[i]) ans = chanel[i];
	}
	return;
}
#endif

int isok(int city,int clor)
{
	int i = 0;
	int j = 0;
	int num = 0;

	for (i = 1; i <= R;i++)
	{
		if (0 == adjacen[city][i]) continue;
		if (clor == chanel[i]) return 0;
		num += 1;
		if (num == adnum[city]) return 1;
	}
	return 1;
}

int max()
{
	int channelnum = 0;
	int i = 0;
	for (i = 1; i <= R;i++)
	{
		if (channelnum<chanel[i])
		{
			channelnum = chanel[i];
		}
	}
	return channelnum;
}

//还是要用dfs来做,dfs做就是找到所有的涂色方法,然后找到最小的那个值。。。。

void dfs(int city,int clor)
{
	int i = 0;
	int j = 0;
	if (city == (R+1))  //所有接收器都选择好了频道
	{
		if (ans > max())
		{
			ans = max();
		}
		tusenum += 1;
		return;
	}
	//这里还借鉴了四色理论
	//最多只可能涂四种颜色
	//for (i = city; i <= R; i++)
	//{
		for (j = 1; j <= 4;j++)  //只试四种算是剪枝了
		{
			if (isok(city, j))
			{
				chanel[city] = j;
				dfs(city + 1, j);
				chanel[city] = 0;  //不能置回0,置会0如果没有符合的,那岂不是就直接这个channel都是0了,那不对啊
			}
		}
	//}
	return;
}


int main()
{
	int i = 0;
	freopen("input.txt","r",stdin);
	while ((1 == scanf("%d",&R)) &&(0 != R)) //R个点
	{
		init();
		for (i = 0; i < R;i++)
		{
			scanf("%s", &str);
			parseit();
		}
		
		dfs(1,0);
		if (1 == ans)
		{
			printf("%d channel needed.\n", ans);
		}
		else
		{
			printf("%d channels needed.\n", ans);
		}
		
	}
	return 0;
}

#endif

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值