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; }