题意:构图,如果两点互相影响,则连接一条边。
剩下的就是图着色问题,相连的点不能用同一种颜色,问最少需要多少颜色。
写法一:0ms
#include <iostream>
using namespace std;
bool map[26][26];
int n,ans;
int color[26];
bool check(int position,int color_index)
{
for(int i=0;i<n;i++)
{
if(map[position][i]&&color[i]==color_index) return false; //相邻的且不同色
}
return true;
}
void DFS(int index,int used_color_num)
{
if(used_color_num>=ans) return;
if(index==n)
{
ans=used_color_num;
return;
}
for(int i=1;i<=used_color_num;i++)
{
if(check(index,i))
{
color[index]=i;
DFS(index+1,used_color_num);
color[index]=0; //需要回溯,因为如果2个不满足的话回溯到初始状态搜索3个颜色的情况
}
}
used_color_num++;
color[index]=used_color_num;
DFS(index+1,used_color_num);
color[index]=0;
}
int main()
{
char temp_str[30];
while(scanf("%d",&n)&&n)
{
memset(map,0,sizeof(map));
memset(color,0,sizeof(color));
ans=INT_MAX;
for(int i=0;i<n;i++)
{
scanf("%s",temp_str);
for(int j=2;temp_str[j]!='/0';j++)
{
map[i][temp_str[j]-'A']=true;
}
}
DFS(0,0);
if(ans==1) printf("%d channel needed./n",ans);
else printf("%d channels needed./n",ans);
}
return 0;
}
写法二:
#include <iostream>
#include <cstring>
using namespace std;
int map[27][27],chan[27];
int mmin,n;
bool ok(int i, int c) //判断颜色是否合法
{
for(int j=0;j<n;++j)
if(map[i][j]&&c==chan[j]) //与之相邻并且颜色相同
return false;
return true;
}
void dfs(int i)
{
if(i==n)
{
int m=0;
for(int j=0;j<n;++j)
if(m<chan[j])m=chan[j];
if(mmin>m)mmin=m;
}
else
{
for(int c=0;c<4;++c) //四色原理,只用试4种颜色即可
{
if(ok(i,c))
{
chan[i]=c;
dfs(i+1);
chan[i]=-1;
}
}
}
}
int main()
{
char ch[50];
while(cin>>n&&n!=0)
{
memset(map,0,sizeof(map));
for(int i=0;i<n;++i)
{
cin>>ch;
if(strlen(ch)>2)
{
for(int j=2;j<strlen(ch);++j)
{
int k=ch[j]-65;
map[i][k]=map[k][i]=1;
}
}
}
for(int k=0;k<n;++k)chan[k]=-1;
mmin=5; //最多4种颜色,所以令mmin=5
dfs(0);
mmin++;
if(mmin>1)
cout<<mmin<<" channels needed."<<endl;
else cout<<mmin<<" channel needed."<<endl;
}
return 0;
}
写法三:
import java.util.*;
import java.io.*;
/*
*【分析】利用四色定理,直接枚举颜色数+DFS,其中DFS是暴力枚举每个顶的颜色,以便找到一个可行解。
*/
public class Main{
public static int[][] g=new int[26][26];
public static int solve(int n){
int i,j,cnum;
boolean tag=true;
// 无边图只用1色即可
for(i=0;i< n && tag;i++){
for(j=i+1;j< n && tag;j++){
if(g[i][j]==1)
tag=false;
}
}
if(tag)
return 1;
for(cnum=2;cnum<=4;cnum++) // 枚举答案+dfs
{
int[] x=new int[n];
Arrays.fill(x,-1); //这也算是相当于上面两种写法的回溯
if(DFS(x,0,cnum,n))
return cnum;
}
return -1;
}
//DFS的复杂度是颜色数^顶点数(4^26,其中可行性剪枝剪掉了很多分支)
public static boolean DFS(int[] x,int vnum, int cnum,int n){
if(vnum == n) return true; // v的顶点都上色,可行解
for(int i=0;i< cnum;i++){ // 如果某个顶点没有颜色填,返回上一层
x[vnum] = i;
if(check(vnum,x,i,n))
if(DFS(x,vnum+1,cnum,n)) // 合法,枚举下一个顶点
return true;
}
return false;
}
// 判断相邻的顶点是否有涂过这种颜色
public static boolean check(int vnum,int[] x,int t,int n){
boolean find=true;
for(int i=0;i< n && find;i++){
if(g[vnum][i]==1 && x[i]==t)
find=false;
}
return find;
}
public static void main(String rgs[]) throws Exception
{
Scanner cin = new Scanner(new BufferedInputStream(System.in));
int i,j,n=cin.nextInt();
while(n!=0){
for(i=0;i< n;i++)
Arrays.fill(g[i],0);
for(i=0;i< n;i++){
String s = cin.next();
for(j=2;j< s.length();j++)
g[i][s.charAt(j)-'A']=1;
}
int count=solve(n);
if(count==1)
System.out.println(count+" channel needed.");
else
System.out.println(count+" channels needed.");
n=cin.nextInt();
}
}
}