模板如下(DP + DFS),
/home/a/j/nomad2:cat mcp.CPP #include <iostream> using namespace std; const int V = 7; int g[V][V], dp[V], stk[V][V], mx; void display() { cout << "stk[][]:" <<endl; for(int i = 0; i < V; i++) { for(int j = 0; j < V; j++) { cout << stk[i][j] << " "; } cout << endl; } cout << endl; cout << "dp[]:" << endl; for(int i = 0; i < V; i++) { cout << dp[i] << " "; } cout << endl; cout << endl; } int dfs(int n, int ns, int dep) { if(0 == ns) { if(dep > mx) { mx = dep; } return 1; } int i, j, k, p, cnt; for(i=0; i <ns; i++) { k = stk[dep][i]; cnt = 0; if (dep +n -k <= mx) return 0; if (dep + dp[k] <= mx) return 0; for(j=i+1; j < ns; j++) { p=stk[dep][j]; if(g[k][p]) { stk[dep+1][cnt++] = p; } } dfs(n, cnt, dep+1); } return 1; } int clique(int n) { int i, j, ns; for(mx = 0, i = n-1; i>=0; i--) { for(ns=0,j=i+1; j < n; j++) { if(g[i][j]) { stk[1][ns++] = j; } } display(); dfs(n, ns, 1); dp[i] = mx; } return mx; } void input() { int v; for(int i = 0; i < V; i++) { for(int j = 0; j < V; j++) { cin >> v; g[i][j] = v; } } } int main() { input(); cout << clique(V) << endl; display(); }
测试如下:
/home/a/j/nomad2:cat input 0 1 1 1 0 1 0 1 0 1 0 1 0 1 1 1 0 1 1 0 0 1 0 1 0 1 1 1 0 1 1 1 0 1 1 1 0 0 1 1 0 1 0 1 0 1 1 1 0 /home/a/j/nomad2:cat input |./a.out stk[][]: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 dp[]: 0 0 0 0 0 0 0 stk[][]: 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 dp[]: 0 0 0 0 0 0 1 stk[][]: 0 0 0 0 0 0 0 5 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 dp[]: 0 0 0 0 0 2 1 stk[][]: 0 0 0 0 0 0 0 4 5 6 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 dp[]: 0 0 0 0 3 2 1 stk[][]: 0 0 0 0 0 0 0 3 4 6 0 0 0 0 5 6 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 dp[]: 0 0 0 4 3 2 1 stk[][]: 0 0 0 0 0 0 0 2 4 6 0 0 0 0 4 6 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 dp[]: 0 0 4 4 3 2 1 stk[][]: 0 0 0 0 0 0 0 1 2 3 5 0 0 0 4 6 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 dp[]: 0 4 4 4 3 2 1 4 stk[][]: 0 0 0 0 0 0 0 1 2 3 5 0 0 0 5 6 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 dp[]: 4 4 4 4 3 2 1
关于剪枝的理解,参考:http://hi.baidu.com/xuhanqiu/blog/item/0fb64fdbc9dc92d2b6fd48f0.html,如下
1. 剪枝1:常用的指定顺序, 即枚举第i个顶后, 以后再枚举时枝考虑下标比大它的, 避免重复。
2. 剪枝2:自己开始从前往后的枚举顶点, TLE两次. 后来从后往前枚举顶点,发现可以利用顶点之间的承袭性.我用num[i] 记录的可选顶点集合为 V[i, i+1, ... , n] 中的最大团数目, 目标是求num[1].
分析易知, num[i] = num[i+1] 或者 num[i]+1 (num[n...1] 具有非降的单调性,从后往前求)
由这个式子以及num[]信息的记录,使得我们可以增加两处剪枝:
3.上/下剪枝:假设当前枚举的是顶点x, 它的第一个邻接顶是i (标号一定比x大,即num[i]已经求出) 我们可以知道, 若 1 + num[i] <= best, 那么是没没要往下枚举这个顶点x了,因为包含它的团是不可能超过我们目前的最优值的。
4. 立即返回剪枝: 由于num[i]最大可能为num[i+1]+1, 所以在枚举顶点i时,只要一更新best,可知此时的num[i]就为num[i+1]+1了,不需要再去尝试找其他的方案了,所以应立即返回.
POJ: 1419, 1129,3692(TLE)