Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 12777 | Accepted: 6547 |
Description
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
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
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.
传送门:题解
此题极其特别,因为是平面图,我们可以利用它的对偶图的面着色来处理,由于四色猜想已被计算机证明(尽管很多数学家不承认,但结论确实是对的),如果你也投靠那些不承认的数学家,那也没有问题,五色定理是已经被证明的,因此可以利用这个来剪枝,其实剪不剪复杂度都是O(n^2),但是对于n很大时,剪枝要快得多,这里数据量较小,就不剪枝了,剪枝也很方便,改几处代码就可以了,留给你们思考。
代码(未剪枝):
#include<cstdio>
#include<iostream>
#include<cstring>
#define Maxn 30
using namespace std;
char s[Maxn];
int adj[Maxn][Maxn];
int vis[Maxn],color[Maxn];
int dye(int n){ //染色范围[0,n-1]
int ans=-1;
memset(color,-1,sizeof color);
for(int i=0;i<n;i++){
memset(vis,0,sizeof vis);
for(int j=0;j<n;j++)
if(adj[i][j]&&color[j]!=-1)
vis[color[j]]=1;
for(int j=0;j<n;j++)
if(!vis[j]){
color[i]=j;
ans=max(ans,j);
break;
}
}
return ans+1;
}
int main()
{
int n;
while(cin>>n,n){
memset(adj,0,sizeof adj);
for(int i=0;i<n;i++){
cin>>s;
for(int j=2;s[j];j++)
adj[i][s[j]-'A']=adj[s[j]-'A'][i]=1;
}
int ans=dye(n);
if(ans==1) printf("1 channel needed.\n");
else printf("%d channels needed.\n",ans);
}
return 0;
}
特别补上:
poj数据太弱!
这题没那么容易,上面的解法是错误的,特此纠正,顺序染色得到的不一定是最优解。
错误样例:
5
A:D
B:C
C:BDE
D:AC
E:C
正解应该是2,程序跑出来是3.
还有一种解法就是dfs贪心染色,这种做法我也写了程序,poj上反而WA了,说来奇怪,貌似该方法看上去是对的。但还是不要想当然,可以负责任地告诉你,贪心思想也是错的,得到的也不一定是最优解。
错误样例:
6
A:BEF
B:AC
C:BD
D:CEF
E:ADF
F:ADE
正解应该是3,程序跑出来是4.
正确的要怎么做?要我说就是纯暴力(把所有情况都试探一下),当然利用四色定理将复杂度优化下来,我优化到了O(3^n)。
正确的代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define Maxn 30
using namespace std;
char s[Maxn];
int adj[Maxn][Maxn];
int color[Maxn];
int n;
int ans;
bool check(int u,int c){
for(int v=0;v<u;v++)
if(adj[u][v]&&color[v]==c)
return false;
return true;
}
void dfs(int d){
if(d==n){
ans=min(ans,*max_element(color,color+n));
return;
}
for(int c=1;c<4;c++)
if(check(d,c)){
color[d]=c;
dfs(d+1);
}
}
void solve(){
color[0]=1;
ans=4;
dfs(1);
}
int main()
{
while(cin>>n,n){
memset(adj,0,sizeof adj);
for(int i=0;i<n;i++){
cin>>s;
for(int j=2;s[j];j++)
adj[i][s[j]-'A']=adj[s[j]-'A'][i]=1;
}
solve();
if(ans==1) printf("1 channel needed.\n");
else printf("%d channels needed.\n",ans);
}
return 0;
}