HDU 1530 最大团问题 dfs+枝剪+dp

Maximum Clique

Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 6676 Accepted Submission(s): 3388

Problem Description
Given a graph G(V, E), a clique is a sub-graph g(v, e), so that for all vertex pairs v1, v2 in v, there exists an edge (v1, v2) in e. Maximum clique is the clique that has maximum number of vertex.

Input
Input contains multiple tests. For each test:

The first line has one integer n, the number of vertex. (1 < n <= 50)

The following n lines has n 0 or 1 each, indicating whether an edge exists between i (line number) and j (column number).

A test with n = 0 signals the end of input. This test should not be processed.

Output
One number for each test, the number of vertex in maximum clique.

Sample Input
5
0 1 1 0 1
1 0 1 1 1
1 1 0 1 1
0 1 1 0 1
1 1 1 1 0
0

Sample Output
4

更新最大团的节点数的时候从后往前更新,用dp【i】记录第i个节点可以获得的最大团的节点数,然后向前推进添加节点,如果添加的这个节点可以联通的节点数加上dp[i] 都小于已经找到的ans, 那么添加上这个点肯定不可能成为最优解, 那么就舍弃这个点,继续寻找下一个点,从后往前寻找完全部的团,然后记录的最大的ans,就是最大团的解,在添加节点的过程中用dp【i】进行枝剪。
#include<iostream> 
#include<algorithm>
#include<cstring>
using namespace std;
int n;
int map[55][55];
int now[55];
int dp[55];
int ans;
void dfs(int x, int sum){ // x->当前的节点  sum--> 当前的最多的节点数 
	if(sum > ans ) ans = sum;
	int can = 0; // x这个节点可以联通的节点数 
	int temp[55]; 
	for(int i = x + 1; i <= n; i++){
		temp[i] = now[i];//用来找下一个节点更新now 
		if(now[i]) can++;
	} 
		
	if(sum + can <= ans ) return; //如果当前的x这个节点联通的节点数加上已经选择的节点数还小于ans 
								//	说明他最大也不可能超过ans,所以就枝剪 
	for(int i  = x + 1; i <= n; i++){ //寻找下一个节点 
		if(!temp[i]) continue;//说明x这个节点和i这个节点不联通 那么就继续寻找下一个节点
		if(dp[i] + sum <= ans) continue;// 最大的可行解数都小于ans 所以舍弃这个i节点
		for(int j = x +1; j <= n; j++)
			now[j] = temp[j]&map[i][j]; //now【j】表示与x联通 同时又与i联通 
			dfs(i, sum + 1);  
	} 
}
int main(){
	while(scanf("%d", &n)!=EOF){
		memset(dp, 0, sizeof(dp));
		if(n == 0) break;
		for(int i = 1; i <= n; i++)
			for(int j = 1; j <= n; j++)
				scanf("%d", &map[i][j]);
				
		ans = dp[n] = 1;//最后一个点是1;就是他本身
		for(int i = n - 1; i >= 1; i--){
			for(int j = 1; j <= n; j++)
				now[j] = map[i][j]; //代表当前i这个节点可通过的(连用)的点
				dfs(i, 1); //算上I他本身 当前最大节点数就是他本身 1
				dp[i] = ans; //更新 当前的最大节点数 
		} 
		printf("%d\n", ans);
	} 
	
	return 0;
}
发布了28 篇原创文章 · 获赞 22 · 访问量 1040

猜你喜欢

转载自blog.csdn.net/qq_45432665/article/details/103210810