Channel Allocation
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 10300 Accepted: 5245
Description
When a radio station is broadcasting over avery large area, repeaters are used to retransmit the signal so that everyreceiver has a strong signal. However, the channels used by each repeater mustbe 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 aprecious resource, the number of channels required by a given network ofrepeaters should be minimised. You have to write a program that reads in adescription of a repeater network and determines the minimum number of channelsrequired.
Input
The input consists of a number of maps ofrepeater networks. Each map begins with a line containing the number ofrepeaters. This is between 1 and 26, and the repeaters are referred to byconsecutive 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 zerorepeaters indicates the end of input.
Following the number of repeaters is a listof adjacency relationships. Each line has the form:
A:BCDH
which indicates that the repeaters B, C, Dand H are adjacent to the repeater A. The first line describes those adjacentto repeater A, the second those adjacent to B, and so on for all of therepeaters. If a repeater is not adjacent to any other, its line has theform
A:
The repeaters are listed in alphabeticalorder.
Note that the adjacency is a symmetricrelationship; 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 adjacentrepeaters does not have any line segments that cross.
Output
For each map (except the final one with norepeaters), print a line containing the minumum number of channels needed sothat no adjacent channels interfere. The sample output shows the format of thisline. Take care that channels is in the singular form when only one channel isrequired.
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.
Source
Southern African 2001
题目大意:
邻近的转发器使用不同的频道,那么求出在一个范围内的转发器所需的数量最少。
编程任务:
读取转发器网络的描述信息,计算出所需的频道的最小使用量;
分析:
相邻的转发器使用不同的频道,也就是说相邻的顶点着不同的颜色,那么可转化为点着色的问题,书上说需要的颜色不超过4种,查略了下图论知识,还是不知道为什么,不过不影 响我们解题,我们只要从第一种颜色开始不断地遍历,按照需要不断的增加颜色,直到给每个顶点染色即可。
点着色的一般的做法是从1~n种颜色分别广度遍历图,直到发现k中颜色能满足要求,则返回;(也就是说需要广度遍历图K次)
核心:(该算法的过程如下所示:先从顶点1开始,依次着色,但是每次着色都必须取可以选择颜色的最小值)
比如先从顶点A,B,C,D,E,F染色,分别对应颜色的种类,给G染上色1~5,如果发现不能染色成功,说明不能用5种颜色不能完全上色;
Java代码如下所示:
package ACM;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Scanner;
public class Main {
private int[][] g ;
private int[] status ;
public Main(int n) {
g = new int[n][n];
status = new int[n];
resetAllVertex();
}
// 因为是无向的图
public void addEdge(char start, char end) {
int startInt = (int) start - (int) 'A';
int endInt = (int) end - (int) 'A';
g[startInt][endInt] = 1;
// g[endInt][startInt] = 1;
}
private void resetAllVertex() {
// TODO Auto-generated method stub
for (int i = 0; i < status.length; i++) {
Arrays.fill(g[i], 0);
}
Arrays.fill(status, 0);
}
// 广度遍历
public boolean BFSTraverse(int colorCount) {
// 先任意选择一个节点出发,然后一次广度遍历可能需要多次广度遍历,可能会存在两个鼓励的图呢?
// 考虑要全面哈;
Arrays.fill(status, 0);
int start;
while ((start = hasIndexNotZero()) != -1) {
if (!BFS(start, colorCount)) {
return false;
}
}
return true;
}
private boolean BFS(int start, int colorCount) {
// TODO Auto-generated method stub
LinkedList<Integer> llist = new LinkedList<Integer>();
llist.add(start);
status[start] = 1;
boolean flagSucess;
int vert;
while (llist.size() > 0) {
vert = llist.remove();
flagSucess = true;
int i;
int currentColor;
// 颜色选择,也就是说先从最小值的颜色选择,如果不能成功,那么选择颜色更大的值;
for (currentColor = 1; currentColor <= colorCount; currentColor++) {
for (i = 0; i < status.length; i++) {
if (g[vert][i] == 1 && status[i] == 0) {
// 判断i节点染色为currentColor的时候,是否能成功,不能成功那么需要break;
// 成功的话那么添加到队列中;
boolean flag = true;
for (int j = 0; j < status.length; j++) {
if (g[i][j] == 1) {
if (status[j] == currentColor) {
flag = false;
flagSucess = false;
break;
}
}
}
if (!flag) {
break;
} else {
status[i] = currentColor;
flagSucess = true;
llist.add(i);
currentColor = 0;
}
}
}
// 说明染色成功了
if (flagSucess && i == status.length) {
break;
}
}
if (!flagSucess) {
return false;
}
}
return true;
}
// 从数组status中找出下标不为0的值,并返回该下标,也就是节点哈;
private int hasIndexNotZero() {
// TODO Auto-generated method stub
for (int i = 0; i < status.length; i++) {
if (status[i] == 0) {
return i;
}
}
return -1;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int n;
String str = null;
Main graph = null;
char tempStart;
char tempEnd;
Scanner cin = new Scanner(new BufferedInputStream(System.in));
try {
n = cin.nextInt();
while (n != 0) {
graph = null;// 没啥子意义,为了通知gc销毁
graph = new Main(n);
for (int i = 0; i < n; i++) {
str = cin.next().trim();
if (str.length() > 2) {
for (int j = 2; j < str.length(); j++) {
graph.addEdge(str.charAt(0), str.charAt(j));
}
}
}
int needColor;
// 开始着色(从第一种颜色开始尝试)
for (needColor = 1; needColor <= n; needColor++) {
if (graph.BFSTraverse(needColor)) {
break;
}
}
if (needColor == 1) {
System.out.println("1 channel needed.");
} else {
System.out.println(needColor + " channels needed.");
}
n = cin.nextInt();
}
} catch (NumberFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
真是万事开头难,本来很简单的程序,在POJ1129上提交,总是提示Rumming Error,调试了半天,依然没有解决,后来发现原来是不能加包名。。囧。。不过还好,也算解决了。。