四色猜想

百度百科
//四色猜想(四色猜想的证明于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");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值