C - E003 信道分配

Problem Description

当无线电台在一个非常大的区域上传播信号时,为了每个接收器都能得到较强信号,使用转发器转发信号。然而,需要仔细地选择每个转发器使用的频道,以使附近的转发器不彼此干扰。如果邻近的转发器使用不同的频道,条件就得到满足。
因为无线电波的频谱是宝贵的资源,转发器所需频道的数量应减到最少。编程任务:读取转发器网络的描述信息,并计算出所需频道的最小使用量。

Input

输入包含许多转发器网络图。每幅图的第一行是转发器数目(1~26)。转发器用连续的大写字母表示,从A开始。例如,10个转发器的名称分别是A,B,C,…,I和J。当转发器的个数是0时,表示输入结束。
转发器数目之后,是其邻近关系的列表。每行的格式为
A:BCDH
表示转发器B、C、D和H与转发器A邻近。第一行描述与转发器A邻近的,第二行描述与B邻近的,直到描述完所有的转发器。如果某个转发器不与其他转发器相邻,它的形式为
A:
转发器依字母顺序列出。
注意:相邻是对称的关系;如果A与B相邻,那么B与A也相邻。因为转发器位于水平面内,由相邻的转发器构成的网络图没有相交的线。

Output

对于每幅图(除了最后一个没有转发器),输出一行,是转发器不互相干扰所需的最少频道数。输出格式参考样例输出。注意:频道数为1的话,“channel”为单数。

Sample Input

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

Sample Output

1 channel needed.
3 channels needed.

解题分析

本题的转发器网络相当于一个无向图,而邻近的转发器使用不同的频道相当于无向图的着色问题。

(1)样例分析
样例2和样例3的转发器网络图,为确保邻近的转发器使用不同的频道,样例数据2需要使用3个频道(转发器A、B和C各不一样,转发器D的频道和A一样):样例数据3需要使用4个频道(因为这些转发器两两相邻)。

(2)构造无向图
使用数组g存储转发器网络的无向图:
bool g[26][26];
转发器的数量:
int n;
对每个转发器的邻接关系,对称地存储于数组g中即可。

(3)着色的实现
因为颜色不超过4种,所以有如下两种情况:
所有的转发器互不相邻,只要着一种颜色;
用两种或三种颜色去着色,看看是否能够成功着色。如果都不能实现着色,那就是4种颜色。
使用函数dfs()实现着色的算法:
Bool dfs(int id, int color)
形参id是起始着色的结点,color是限制的着色数量。
当某一结点id使用颜色i时,在已经着色的结点中,搜索是否使用过这种颜色。如果该颜色已经使用,则换一种颜色;否则搜索下一个结点。当所有的结点着色完成,返回成功标志true;当颜色数color都用完了,还不能给所有结点着色,则返回失败标志false。

代码

#include 
#include 

bool g[26][26];		//存储无向图
int used[26];		//已经使用的颜色
int n;

//深度优先搜索,实现着色
//形参id是起始着色的结点,color是限制的着色数量
bool dfs(int id, int color)
{
     
	int i, j;
	bool flag;		//着色成功的标志
	//在规定的颜色数中着色
	for(i = 0; i < color; i++)
	{
     
		flag = true;
		//结点id使用第i号颜色
		used[id] = i;
		//判断相邻结点是否使用了该颜色
		for(j = 0; j < id; j++)
			if(g[id][j] && used[id] == used[j])
			{
     
				//该颜色已经使用,换一种颜色
				flag = false;
				break;
			}
		//该颜色有效,当所有结点着色完毕返回true,或者给下一个结点着色
			if(flag && (id == n-1 || dfs(id+1,color)))
				return true;
	}
	//使用color个颜色没有实现全部着色
	return false;
}

int main()
{
     
	int i, j;
	bool one;	//只需要一种颜色的标志
	char adjacent[50];
	while(scanf("%d", &n) && n)
	{
     
		memset(g, 0, sizeof(g));
		memset(used, 0, sizeof(used));
		//构造无向图
		one = true;
		for(i = 0; i< n; i++)
		{
     
			scanf("%s", adjacent);
			//从第3个字符起,是邻接关系结点
			for(j = 2; adjacent[j]; j++, one = false)
			{
     
				//对称
				g[i][adjacent[j] - 'A'] = true;
				g[adjacent[j] - 'A'][i] = true;
			}
		}
		if(one)
			printf("1 channel needed.\n");
		else if(dfs(1,2))
			printf("2 channels needed.\n");
		else if(dfs(1,3))
			printf("3 channels needed.\n");
		else
			printf("4 channels needed.\n");
	}
	return 0;
}

你可能感兴趣的:(算法2期末复习,算法)