模板如下(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)