百度百科
//四色猜想(四色猜想的证明于1976年由美国数学家-阿佩尔(Kenneth Appel)与哈肯(Wolfgang Haken)借助计算机完成,称为四色定理)
//猜想简述 : 将平面任意地细分为不相重叠的区域,每一个区域总可以用1234这四个数字之一来标记而不会使相邻的两个区域得到相同的数字
四色定理的“相邻”是指两块多边形地区“至少一条边重合”才为之相邻
“至少一条边重合”同时也隐含了“任意边(线段)不正规相交
//同样是世界近代三大数学难题之一, 所以还是了解为好.
//有一部分的题也是需要用到这个猜想内容的, 一般就是深搜填颜色时用于剪枝. 当
几道例题 :
POJ — 1129
//题意 : 转化一下就是在一个平面中有一些点, 给出这些点的边信息, 如果某两个点之间有边, 说明这两个点是相邻的. 保证不有边相交. 对这些点进行染色, 问最少用多少种颜色, 使得相邻的点不是同一颜色.
//一看感觉就是用四色定理进行dfs剪枝, 但是我发现直接爆搜也是可以的, 因为后面扩充的点并不是这么多, 主要是总的点数不多, 才26个. 那么我这里用不用我都贴下代码.
AC Code(爆搜)
/** @Cain*/
bool mapp[30][30];
int color[30];
int n,res;
bool flag;
bool check(int u,int x)
{
for(int i=1;i<=n;i++){
if(mapp[u][i] && color[i] == x)
return false;
}
return true;
}
void dfs(int u,int sum)
{
if(flag) return ;
if(u>n) {flag = true; return ;}
for(int i=1;i<=sum;i++){
if(check(u,i)){
color[u] = i;
dfs(u+1,sum);
}
}
if(!flag){ //颜色不够涂, 那么就加一种.其实也可以发现sum不会大于4.
res++;
dfs(u,sum+1);
}
}
void solve()
{
while(~scanf("%d",&n) && n){
Fill(mapp,false);
Fill(color,0);
int maxx = 0;
while(n--){
char s[30];
scanf("%s",s);
int len = strlen(s);
maxx = max(maxx,s[0]-'A'+1);
for(int i=2;i<len;i++){
mapp[s[0]-'A'+1][s[i]-'A'+1] = true;
}
}
n = maxx ; res = 1;
flag = false;
dfs(1,1);
if(res == 1) printf("1 channel needed.\n");
else printf("%d channels needed.\n",res);
}
}
AC Code(四色剪枝)
/** @Cain*/
bool mapp[30][30];
int color[30];
int n,res;
bool flag;
bool check(int u,int x)
{
for(int i=1;i<=n;i++){
if(mapp[u][i] && color[i] == x)
return false;
}
return true;
}
void dfs(int u)
{
if(flag) return ;
if(u>n) {flag = true; return ;}
for(int i=1;i<=4;i++){ //最多四中颜色.
if(flag) break;
res = max(res,i); //记录最多用到了那种颜色.
if(check(u,i)){
color[u] = i;
dfs(u+1);
}
}
}
void solve()
{
while(~scanf("%d",&n) && n){
Fill(mapp,false);
Fill(color,0);
int maxx = 0;
while(n--){
char s[30];
scanf("%s",s);
int len = strlen(s);
maxx = max(maxx,s[0]-'A'+1);
for(int i=2;i<len;i++){
mapp[s[0]-'A'+1][s[i]-'A'+1] = true;
}
}
n = maxx ; res = 1;
flag = false;
dfs(1);
if(res == 1) printf("1 channel needed.\n");
else printf("%d channels needed.\n",res);
}
}
HDU — 5113
// 给你一个n x m的棋盘, 和k中颜色, 并给出每种颜色最多可以用的次数, 问有多少种涂色方式使得最后没有相邻的格子是同一种颜色.
//当然还是深搜做. 一行一行的搜. 只是必须加剪枝了, 我直接搜T了, 剪枝就是当还可以填的某一个颜色的次数大于(剩余格子数+1)/2时, 一定不能满足题意, 这种情况下就可以不用再搜下去了. 剪完枝以后我就过了. xx.
AC Code
/** @Cain*/
int res[10][10];
int num[30];
int n,m,k;
bool flag;
void dfs(int x,int y,int yu)
{
if(flag) return ;
if(yu == 0){
printf("YES\n");
flag = true;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
printf("%d%c",res[i][j],j==m?'\n':' ');
}
}
return ;
}
for(int i=1;i<=k;i++){
if(num[i]>(yu+1)/2) return ; //剪枝
}
for(int i=1;i<=k;i++){
if(!num[i]) continue;
if(res[x-1][y] == i || res[x][y-1] == i) continue;
num[i]--;
res[x][y] = i;
if(y+1<=m) dfs(x,y+1,yu-1); //搜当前行
else dfs(x+1,1,yu-1); //搜完了上一行,搜下一行.
num[i]++; //记得回溯后的操作.
res[x][y] = 0;
}
}
void solve()
{
Fill(res,0); flag = false;
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=k;i++) scanf("%d",&num[i]);
dfs(1,1,n*m);
if(!flag) printf("NO\n");
}