:) Ch_someone

Ch_someone

图着色问题

图上的染色问题算是一个挺有名的NP-完全问题了吧

题目描述

    给定无向连通图G 和M 种不同的颜色,用这些颜色为图G 的各顶点着色,每个顶点着一种颜色。如果有一种着色法使G 中每条边的2 个顶点着不同的颜色,则称这个图是M 可着色的。图的M 着色问题是对于给定图G 和M 种颜色,找出所有不同的着色法。对于给定的无向连通图G 和M 种不同的颜色,编程计算图的所有不同的着色法。


输入

   第一行有3 个正整数N,K 和M,表示给定的图G 有N 个顶点和K 条边,M 种颜色。顶点编号为1,2……,N。接下来的K 行中,每行有2 个正整数U, V,表示图G 的一条边(U,V)。

  数据范围:1<N<=100 1<K<=2500 1<M<=6


输出


  不同的着色方案数

 

样例输入


  5 8 4
  1 2
  1 3
  1 4
  2 3
  2 4
  2 5
  3 4
  4 5


样例输出


  48

 

我的解析:

 

    这道题是一道典型的搜索题,需要dfs和一点点优化(剪枝)。

  我们来看一下样例给的这张图。

    为什么是搜索?对于样例来说,每个点我们都有4种颜色可以选择,而在确定完一个点的颜色后又要选取其他点的颜色,并不能与它相连的点重复。于是马上想到要进行搜索。

    搜索的过程:对于每个点,枚举它可能被染的颜色。如果与它相连的点颜色和它相同,那么就换下一个颜色;如果哪个颜色也不能选,那就回到上一个点换颜色(回溯)……

  当确定完最后一个点的颜色后,这就是一个可行解,将答案增加1。

    我们在判断哪个点与这个点(编号为n)连接并颜色相同时,本来是要遍历一遍图上的点的,而这样会超时。其实不需要这样做。只需遍历从编号1 到 编号n-1 的点就行了,因为

  并没有确定编号n以后的点的颜色。这样相对于把点全遍历一遍,能更快一点,算是一个优化吧。

我的代码:

 

#include<cstdio>
#include<algorithm>
using namespace std;
int m,n,k;
int map[105][105];
int color[105];
int ans;
void a(int p)
{
    if(p == n+1)
    {
        ans++;
        return;
    }
    else
    {
        for(int i=1;i<=m;i++)
        {
            int mmp = false;
            for(int j=1;j<=p;j++)
            {
                if(map[p][j] == 1 && color[j] == i)
                {
                    mmp = true;
                    break;
                }
            }
            if(mmp == true) continue;
            color[p] = i;
            a(p+1);
            color[p] = 0;
        }
    }
}
int main()
{
//    freopen("color.in","r",stdin);
//    freopen("color.out","w",stdout);
    scanf("%d%d%d",&n,&k,&m);
    for(int i=1;i<=k;i++)
    {
        int d1,d2;
        scanf("%d%d",&d1,&d2);
        map[d1][d2] = 1;
        map[d2][d1] = 1;
    }
    a(1);
    printf("%d",ans);
    return 0;
}

 

posted on 2018-03-31 15:42  Ch_someone  阅读(5172)  评论(0编辑  收藏  举报

导航