HDU 5823 color II(状压DP)


Problem Description
You are given an undirected graph with n vertices numbered 0 through n-1.

Obviously, the vertices have 2^n - 1 non-empty subsets. For a non-empty subset S, we define a proper coloring of S is a way to assign each vertex in S a color, so that no two vertices in S with the same color are directly connected by an edge. Assume we've used k different kinds of colors in a proper coloring. We define the chromatic number of subset S is the minimum possible k among all the proper colorings of S.

Now your task is to compute the chromatic number of every non-empty subset of the n vertices.


Input
First line contains an integer t. Then t testcases follow.

In each testcase: First line contains an integer n. Next n lines each contains a string consisting of '0' and '1'. For 0<=i<=n-1 and 0<=j<=n-1, if the j-th character of the i-th line is '1', then vertices i and j are directly connected by an edge, otherwise they are not directly connected.

The i-th character of the i-th line is always '0'. The i-th character of the j-th line is always the same as the j-th character of the i-th line.

For all testcases, 1<=n<=18. There are no more than 100 testcases with 1<=n<=10, no more than 3 testcases with 11<=n<=15, and no more than 2 testcases with 16<=n<=18.


Output
For each testcase, only print an integer as your answer in a line.

This integer is determined as follows:
We define the identity number of a subset S is id(S)=∑v∈S2v. Let the chromatic number of S be fid(S).

You need to output ∑1<=id(S)<=2n−1fid(S)×233id(S)mod232.


Sample Input
2
4
0110
1010
1101
0010
4
0111
1010
1101
1010


Sample Output
1022423354
2538351020

Hint

For the first test case, ans[1..15]= {1, 1, 2, 1, 2, 2, 3, 1, 1, 1, 2, 2, 2, 2, 3}


题意:给一个N*N的矩阵,a[i][j]=1表示点i与点j相连。对于N个点有2^n-1个子集,相连的点不能同色,问对于每个子集最少需要多少颜色。

ans[i]表示i(二进制)状态下的最少颜色数,输出结果∑ans[i]×233^i mod 2^32.

#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <cstdlib>
#include <string.h>
#include <vector>
#include <queue>
#include <stack>
#include <ctype.h>
using namespace std;

typedef unsigned int ui;

ui p233[300005];
int temp[300005][20];
int col[300005][20];   //记录i状态xia

void init()     //预处理233的幂次,以及每个状态temp
{
    memset(p233,0,sizeof(p233));
    memset(temp,0,sizeof(temp));
    p233[0]=1;
    for (int i=1;i<=(1<<18);i++)
        p233[i]=p233[i-1]*(unsigned int)233;
    for(int i=0;i<=300000;i++)
    {
        int x=i;
        int cnt=0;
        while(x>0)
        {
            temp[i][cnt]=x%2;
            x/=2;
            cnt++;
        }
    }
}

char ss[20][20];
int maps[20][20];    //存图
ui dp[300005];      //表示i状态时最少需要多少种颜色
int vis[20];

int main()
{
    init();
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(maps,0,sizeof(maps));
        memset(col,0,sizeof(col));
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            scanf("%s",ss[i]);
        }
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(ss[i][j]=='0') maps[i][j]=0;
                else maps[i][j]=1;
            }
        }
        memset(vis,0,sizeof(vis));
        for(int i=0;i<n;i++)    //当状态中只有一个点的时候
        {
            col[1<<i][i]=1;   //这个点颜色标为1
            dp[i]=1;          //这个状态需要一种颜色
        }
        for(int i=1;i<(1<<n);i++)
        {
            int color=n+1;
            int pos=n+1;
            for(int j=0;j<n;j++)
            {
                if(temp[i][j]==1)
                {
                    memset(vis,0,sizeof(vis));
                    for(int k=0;k<n;k++)
                    {
                        if(maps[j][k]==1)
                        {
                            vis[col[i^(1<<j)][k]]=1;    //统计新增加的这个点与哪些颜色相连
                        }
                    }
                    for(int k=1;k<=n;k++)
                    {
                        if(vis[k]==0)
                        {
                            if(color>k)
                            {
                                color=k;   //color表示最小的不相连的颜色
                                pos=j;
                            }
                            break;
                        }
                    }
                }
            }
            for(int j=0;j<n;j++)
            {
                if(temp[i][j]==1)
                {
                    col[i][j]=col[i^(1<<pos)][j];
                }
            }
            col[i][pos]=color;
            if(color>dp[i^(1<<pos)]) dp[i]=dp[i^(1<<pos)]+1;   //如果与所有的颜色都相连,就要新增一种颜色
            else dp[i]=dp[i^(1<<pos)];
        }
        ui res=0;
        for(int i=1;i<(1<<n);i++)
        {
            res=res+p233[i]*dp[i];   //unsigned int自动取膜
        }
        printf("%u\n",res);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值