HDU 1530 Maximum Clique 最大团

题意:给一个图,找图中的最大团,并输出最大团的顶点数。
思路:暴搜。dfs判断每个点在或者不在。加一个剪枝。就是如果剩下的节点+当前已经搜到的最大团的节点<=已经找到的最好结果,就停止搜索。这个剪枝效率蛮低的。 3510ms过的。

http://acm.hdu.edu.cn/showproblem.php?pid=1530

/*********************************************
    Problem : HDU 1530
    Author  : NMfloat
    InkTime (c) NM . All Rights Reserved .
********************************************/

#include <map>
#include <set>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>

#define rep(i,a,b)  for(int i = (a) ; i <= (b) ; i ++) //遍历
#define rrep(i,a,b) for(int i = (b) ; i >= (a) ; i --) //反向遍历
#define repS(it,p) for(auto it = p.begin() ; it != p.end() ; it ++) //遍历一个STL容器
#define repE(p,u) for(Edge * p = G[u].first ; p ; p = p -> next) //遍历u所连接的点
#define cls(a,x)   memset(a,x,sizeof(a))
#define eps 1e-8

using namespace std;

const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
const int MAXN = 1e5+5;
const int MAXE = 2e5+5;

typedef long long LL;
typedef unsigned long long ULL;

int T,n,m;

int fx[] = {0,1,-1,0,0};
int fy[] = {0,0,0,-1,1};

int M[55][55];
int best; //搜出来最大的团大小
int B[55];
int A[55];

bool check(int num,int now) {
    rep(i,1,now) {
        if(!M[num][A[i]]) return false;
    }
    return true;
}

void dfs(int num,int x_x,int now) { //now需要跟随dfs
    if(num == n) {
        if(now > best) {
            best = now;
            rep(i,1,now) B[i] = A[i];
        }
        return ;
    }
    if((n-num + now) > best && check(num+1,now)) { //判断向num+1存在的方向搜索是不是可行的 
        A[++now] = num + 1;
        dfs(num+1,1,now);
        --now;
    }
    if((n-num-1 + now) > best) { //判断向num+1不存在的方向搜索是不是可行的
        dfs(num+1,0,now);
    }
}

void input() {
    rep(i,1,n) rep(j,1,n) scanf("%d",&M[i][j]);
}

void solve() {
    best = 0 ; 
    dfs(0,0,0);
    printf("%d\n",best);
    // rep(i,1,best) printf("%d ",B[i]);
    // puts("");
}

int main(void) {
    //freopen("a.in","r",stdin);
    while(scanf("%d",&n),n) {
        input();
        solve();
    }
    return 0;
}
网上学到的一个版本 2000ms以下,快了1000+ms。
/*********************************************
    Problem : HDU 1530
    Author  : NMfloat
    InkTime (c) NM . All Rights Reserved .
********************************************/

// 要求 图是无向的

#include <map>
#include <set>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <string>
#include <cstdio>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>

#define rep(i,a,b)  for(int i = (a) ; i <= (b) ; i ++) //遍历
#define rrep(i,a,b) for(int i = (b) ; i >= (a) ; i --) //反向遍历
#define repS(it,p) for(auto it = p.begin() ; it != p.end() ; it ++) //遍历一个STL容器
#define repE(p,u) for(Edge * p = G[u].first ; p ; p = p -> next) //遍历u所连接的点
#define cls(a,x)   memset(a,x,sizeof(a))
#define eps 1e-8

using namespace std;

const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
const int MAXE = 2e5+5;

typedef long long LL;
typedef unsigned long long ULL;

const int MAXN = 55;

int T,n,m;

int fx[] = {0,1,-1,0,0};
int fy[] = {0,0,0,-1,1};

int M[MAXN][MAXN];
int dp[MAXN];
int best;

bool dfs(int * id,int top,int cnt) { 
    //id是和当前点有连接的数组,top是这个数组的长度,cnt已经找到的最大团的大小
    //id数组从1到n
    if(!top) { //dfs的结束标志
        if(best < cnt) {
            best = cnt ;
            return true; //代表这次搜索更新了结果
        }
        return false;
    }
    int a[MAXN];
    rep(i,1,top) {
        if(cnt+top-i+1<=best) return false; 
        //(top-1)-i+1是后继节点生效的个数 因为i是从0开始的 , top-i是在逐渐减少的,所有不用考虑后面的状态
        if(cnt+dp[id[i]]<=best) return false; 
        //cnt现在找到的最大团的个数 + dp[id[i]] , dp[id[i]] 是以id[i]开头最大的最大团个数
        //如果cnt+dp[id[i]]<=best就没有搜索的必要了 , 因为dp[id[i+k]] (k >= 1) 必然 <=dp[id[i]];
        int lan = 0;
        rep(j,i+1,top) if(M[id[i]][id[j]]) a[++lan] = id[j]; 
        //有多少个点和id[i]这个点是连接 , a数组是不能预处理的,因为id[]是不确定的  
        if(dfs(a,lan,cnt+1)) return true;
        //因为每一次搜索最多只会让最大独立团的个数+1,所以如果更新过一次,就不用继续搜了。
    }
    return false;
}

int max_clique() {
    int id[MAXN];
    best = 0;
    rrep(i,1,n) {
        int top = 0;
        rep(j,i+1,n) if(M[i][j]) id[++top] = j;
        dfs(id,top,1);
        dp[i] = best;
    }
    return best;
}

void input() {
    rep(i,1,n) rep(j,1,n) scanf("%d",&M[i][j]);    
}

void solve() {
    printf("%d",max_clique());
    puts("");
}

int main(void) {
    //freopen("a.in","r",stdin);
    while(scanf("%d",&n),n) {
        input();
        solve();
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值