zoukankan      html  css  js  c++  java
  • 最大团题目

    hdu1530 Maximum Clique

    题意:给定一个无向图,求最大团数

    分析:求最大团,也就是求一个最大的完全子图,只能靠搜索了,用一个dp数组剪枝

    搜索思路倒是很清晰

    一般思路:

    枚举每一个点,假设选择了这个点,那么最大团组成的集合就可能是由与这个点关联的点的集合组成,接下来就是深搜选择这个集合里面的点的过程了。

    剪枝:

    1)重新排列了访问的顺序,按度数大的先访问

    2)用一个dp[]数组,dp[i]表示i到n-1范围内的点组成的最大团数,那么dp[i-1] 的最大可能值就是 dp[i]+1了,这个可以在搜索过程用来剪枝

    悲剧,怎么改都是1000+ms

    View Code
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int N = 55;
    int dp[N];//dp[i] 表示 [i,n) 范围内的最大团个数
    bool inset[N],g[N][N];
    int n,best,ord[N],deg[N];
    bool found;//记录每次搜索时是否更新
    void Memcpy(bool *d,bool *s)
    {
    for(int i=0;i<n;i++)
    d[i]=s[ord[i]];
    }
    bool cmp(int a,int b)
    {
    return deg[a]<deg[b];
    }
    int find(int start,bool *s)//查找第一个关联的点
    {
    for(int i=start+1;i<n;i++)
    if(s[i])
    return i;
    return -1;
    }
    void clique(bool *s,int start,int len)
    {
    int first=find(start,s),i;
    if(first==-1)
    {
    if(len>best)
    {
    best=len;
    found=true;
    }
    return ;
    }
    bool tmp[N];
    while(first!=-1)
    {
    if(len+n-start<=best || len+dp[first]<=best)
    //已选择的点的个数+剩余点的个数<=最大可能值
    //已选择的点的个数+后面的最大团数<=最大可能值
    return ;
    tmp[first]=false;
    for(i=first+1;i<n;i++)
    tmp[i]=s[i]&g[ord[first]][ord[i]];//i之后与当前集合重叠的点,只有重叠的点才又可能与已选择的点关联
    clique(tmp,first,len+1);
    if(found) return ;
    first=find(first,s);
    }
    }
    int main()
    {
    while(scanf("%d",&n)==1 && n)
    {
    memset(deg,0,sizeof(deg));
    for(int i=0;i<n;i++)
    {
    ord[i]=i;
    for(int j=0;j<n;j++)
    {
    scanf("%d",&g[i][j]);
    deg[i]+=g[i][j];
    }
    }
    sort(ord,ord+n,cmp);//按度数重新排列访问顺序
    best=0;
    dp[n-1]=1;
    for(int i=n-2;i>=0;i--)
    {
    Memcpy(inset,g[ord[i]]);
    found=false;
    clique(inset,i,1);
    dp[i]=best;
    }
    printf("%d\n",dp[0]);
    }
    return 0;
    }

     pku 1419 Graph Coloring

    题意:给定一个无向图,求一个最大点独立集。

    分析:首先由

    最大团数=补图的最大点独立集

    反之亦然,也就是补图的最大团数

    所以,还是直接用模板,只不过要记录一下路径

    View Code
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int N = 101;
    int dp[N];
    bool inset[N],g[N][N];
    int n,best,ord[N],deg[N];
    bool found;
    int set[N],ans[N];
    void Memcpy(bool *d,bool *s)
    {
    for(int i=0;i<n;i++)
    d[i]=s[ord[i]];
    }
    bool cmp(int a,int b)
    {
    return deg[a]<deg[b];
    }
    int find(int start,bool *s)
    {
    for(int i=start+1;i<n;i++)
    if(s[i])
    return i;
    return -1;
    }
    void clique(bool *s,int start,int len)
    {
    int first=find(start,s),i;
    if(first==-1)
    {
    if(len>best)
    {
    best=len;
    for(int i=0;i<best;i++)
    ans[i]=set[i];
    found=true;
    }
    return ;
    }
    bool tmp[N];
    while(first!=-1)
    {
    if(len+n-start<=best || len+dp[first]<=best)
    return ;
    tmp[first]=false;
    set[len]=ord[first];
    for(i=first+1;i<n;i++)
    tmp[i]=s[i]&g[ord[first]][ord[i]];
    clique(tmp,first,len+1);
    if(found) return ;
    first=find(first,s);
    }
    }
    int main()
    {
    int T,m,a,b;
    scanf("%d",&T);
    while(T--)
    {
    scanf("%d %d",&n,&m);
    memset(deg,0,sizeof(deg));
    memset(g,true,sizeof(g));
    for(int i=0;i<n;i++)
    {
    ord[i]=i;
    deg[i]=n;
    }
    while(m--)
    {
    scanf("%d %d",&a,&b);
    a--;b--;
    g[a][b]=false;
    g[b][a]=false;
    deg[a]--;
    deg[b]--;
    }
    sort(ord,ord+n,cmp);
    best=0;
    dp[n-1]=1;
    for(int i=n-2;i>=0;i--)
    {
    Memcpy(inset,g[ord[i]]);
    found=false;
    set[0]=ord[i];
    clique(inset,i,1);
    dp[i]=best;
    }
    sort(ans,ans+dp[0]);
    printf("%d\n%d",dp[0],ans[0]+1);
    for(int i=1;i<dp[0];i++)
    printf(" %d",ans[i]+1);
    printf("\n");
    }
    return 0;
    }

     pku1129  Channel Allocation

    还是模板题

    View Code
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int N = 30;
    int dp[N];
    bool inset[N],g[N][N];
    int n,best,ord[N],deg[N];
    bool found;
    void Memcpy(bool *d,bool *s)
    {
    for(int i=0;i<n;i++)
    d[i]=s[ord[i]];
    }
    bool cmp(int a,int b)
    {
    return deg[a]<deg[b];
    }
    int find(int start,bool *s)
    {
    for(int i=start+1;i<n;i++)
    if(s[i])
    return i;
    return -1;
    }
    void clique(bool *s,int start,int len)
    {
    int first=find(start,s),i;
    if(first==-1)
    {
    if(len>best)
    {
    best=len;
    found=true;
    }
    return ;
    }
    bool tmp[N];
    while(first!=-1)
    {
    if(len+n-start<=best || len+dp[first]<=best)
    return ;
    tmp[first]=false;
    for(i=first+1;i<n;i++)
    tmp[i]=s[i]&g[ord[first]][ord[i]];
    clique(tmp,first,len+1);
    if(found) return ;
    first=find(first,s);
    }
    }
    int main()
    {
    char str[50];
    while(scanf("%d",&n)==1 && n)
    {
    memset(g,false,sizeof(g));
    memset(deg,0,sizeof(deg));
    for(int i=0;i<n;i++)
    {
    ord[i]=i;
    scanf("%s",str);
    for(int j=2;j<strlen(str);j++)
    {
    int t=str[j]-'A';
    g[i][t]=true;
    g[t][i]=true;
    deg[i]++;
    deg[t]++;
    }
    }
    sort(ord,ord+n,cmp);
    best=0;
    dp[n-1]=1;
    for(int i=n-2;i>=0;i--)
    {
    Memcpy(inset,g[ord[i]]);
    found=false;
    clique(inset,i,1);
    dp[i]=best;
    }
    if(dp[0]==1)
    printf("%d channel needed.\n",dp[0]);
    else printf("%d channels needed.\n",dp[0]);
    }
    return 0;
    }

     hdu 1045 Fire Net

    题意:给定一个n*n的矩阵,'.'表示空白区,‘X’表示墙壁,求在该矩阵上放置碉堡的数量的最大值,使得所有碉堡不能相互攻击(墙壁可以挡住攻击)

    分析:将矩阵上的所有点重新标号,0~n*n,同时,将所有可以直接攻击到的点连接起来,这样,题目就转变成了求一个图的最大独立集。

    设墙壁的数量为x

    所以最后可以放置碉堡的数量=最大独立点数-x (最大独立点数里面包含了墙壁数)

    又因为最大独立数=补图的最大团数,所有就可以用最大团解决了。

    View Code
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int N = 20;
    char g[5][5];
    int dir[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
    int dp[N];
    bool inset[N],mat[N][N];
    int r,n,best,ord[N],deg[N],num;
    bool found;
    void Memcpy(bool *d,bool *s)
    {
    for(int i=0;i<n;i++)
    d[i]=s[ord[i]];
    }
    bool cmp(int a,int b)
    {
    return deg[a]<deg[b];
    }
    int find(int start,bool *s)
    {
    for(int i=start+1;i<n;i++)
    if(s[i])
    return i;
    return -1;
    }
    void clique(bool *s,int start,int len)
    {
    int first=find(start,s),i;
    if(first==-1)
    {
    if(len>best)
    {
    best=len;
    found=true;
    }
    return ;
    }
    bool tmp[N];
    while(first!=-1)
    {
    if(len+n-start<=best || len+dp[first]<=best)
    return ;
    tmp[first]=false;
    for(i=first+1;i<n;i++)
    tmp[i]=s[i]&mat[ord[first]][ord[i]];
    clique(tmp,first,len+1);
    if(found) return ;
    first=find(first,s);
    }
    }
    bool check(int x,int y)
    {
    if(x<0||x>=r || y<0 || y>=r)
    return false;
    return true;
    }
    void build()
    {
    num=0;
    memset(mat,true,sizeof(mat));
    for(int i=0;i<n;i++)
    {
    deg[i]=n;
    ord[i]=i;
    }
    for(int i=0;i<r;i++)
    {
    for(int j=0;j<r;j++)
    {
    int a=i*r+j,b;
    if(g[i][j]=='X'){
    num++;
    continue;
    }
    for(int k=0;k<4;k++)
    {
    int x=dir[k][0]+i;
    int y=dir[k][1]+j;
    while(check(x,y) && g[x][y]!='X')
    {
    b=x*r+y;
    mat[a][b]=false;
    deg[a]--;
    deg[b]--;
    x+=dir[k][0];
    y+=dir[k][1];
    }
    }
    }
    }
    }
    int main()
    {
    while(scanf("%d",&r)==1 && r)
    {
    for(int i=0;i<r;i++)
    scanf("%s",g[i]);
    n=r*r;
    build();
    sort(ord,ord+n,cmp);
    best=0;
    dp[n-1]=1;
    for(int i=n-2;i>=0;i--)
    {
    Memcpy(inset,mat[ord[i]]);
    found=false;
    clique(inset,i,1);
    dp[i]=best;
    }
    printf("%d\n",dp[0]-num);
    }
    return 0;
    }
  • 相关阅读:
    〖Linux〗Kubuntu设置打开应用时就只在打开时的工作区显示
    〖Linux〗Kubuntu, the application 'Google Chrome' has requested to open the wallet 'kdewallet'解决方法
    unity, dll is not allowed to be included or could not be found
    android check box 自定义图片
    unity, ios skin crash
    unity, Collider2D.bounds的一个坑
    unity, ContentSizeFitter立即生效
    类里的通用成员函数应声明为static
    unity, Gizmos.DrawMesh一个坑
    直线切割凹多边形
  • 原文地址:https://www.cnblogs.com/nanke/p/2385989.html
Copyright © 2011-2022 走看看