Kattis mapcolouring(状压dp)

刚知道vj上查看别人代码,看不到汉字。。。我理解的都注明后边了。

#include <bits/stdc++.h>
#define ll long long
#define met(a, b) memset(a, b, sizeof(a))
#define rep(i, a, b) for(int i = a; i <= b; i++)
#define bep(i, a, b) for(int i = a; i >= b; i--)
#define pb push_back
#define mp make_pair
#define debug cout << "KKK" << endl
#define ls num*2
#define rs num*2+1
#define re return 0 
using namespace std;
const ll mod = 1e9+9;
const double PI = acos(-1);
const ll INF = 4e18+1;
const int inf = 1e9 + 15;
const double eps = 1e-7;
const int maxn = 1e5 + 5;
bool ma[16][16];
int dp[1<<16]; // dp[i] 表示给i状态染色所需最小的颜色数。i状态是i对应的二进制,如果某位1,表示该位被染色。

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int t; cin >> t;
    while(t--){
        int m, n; cin >> n >> m;
        int u, v; met(ma, 0);
        rep(i, 1, m){
            cin >> u >> v;
            ma[u][v] = ma[v][u] = 1;
        }

        rep(i, 1, (1 << 16) - 1){
            bool flag = 1;

            //先判断1种颜色能不能染
            rep(x, 0, n-1) if(i & (1<<x))
                rep(y, 0, n-1) if(i & (1<<y)) 
                    if(ma[x][y]) flag = 0; //相连的边都被染色了,不行。
            
            if(flag) dp[i] = 1; // 如果行,这种状态就是1。
            else{
                dp[i] = 10000; //初始化
                for(int j = (i-1)&i; j > 0; j = (j-1)&i){ //这个真牛逼,j是枚举了所有i的排列组合。(x&(x-1))是让二进制最后一位1变成0。比如x = 1010.操作后是1000。
                                //然后这个(j-1) & i。自己随便找个例子就明白了。比如i = 10101. j会遍历10100 10001 10000 00101 00100 00001枚举了位数是1的排列组合    
                    dp[i] = min(dp[i], dp[i-j]+dp[j]); //相当于i-j状态和j状态用的颜色都不同,。
                }
            }
        }
        if(dp[(1<<n)-1] <= 4) cout << dp[(1<<n)-1] << endl;
        else cout << "many" << endl;
    }
    re;
}

 

posted @ 2020-05-09 15:02  philo_zhou  阅读(168)  评论(0编辑  收藏  举报