最大团问题 MCP

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

你可能感兴趣的:(最大团问题 MCP)