hdu 2489 Minimal Ratio Tree 最小生成树+状态压缩

题目问的就是,从n个点中选m个点,生成树值和点的权值比例最小,用二进制来枚举全部情况。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=17;
const int MAXN=1<<N;
const double inf=1e10;
int g[N][N],dist[N],vis[N],use[MAXN],n,m,pe[N];


int get(int k)
{
    int ret=0;
    while(k)
    {
        ret+=k%2;
        k/=2;
    }
    return ret;
}

double prim(int k)
{
    int sum_n,sum_m,i,j,u,w;
    memset(vis,0,sizeof(vis));
    for(i=0; i<n; i++)
        if(k&(1<<i))
        {
            u=i;
            break;
        }
    sum_m=0;
    sum_n=pe[u];
    for(i=0; i<n; i++)
    {
        if((1<<i)&k)
            dist[i]=g[u][i];
        else
            dist[i]=1024;
        //printf(" %d",dist[i]);
    }
    //printf("\n");
    vis[u]=1;
    int cnt=get(k);
    if(cnt!=m) return inf;
    //printf(" %d %d %d\n",k,u,cnt);
    for(i=2; i<=cnt; i++)
    {
        //if(k==11) printf("%d %d\n",i,cnt);
        u=-1;
        w=1024;
        for(j=0; j<n; j++)
        {

            if(vis[j]==1) continue;
            if(((1<<j)&k)==0) continue;
            //printf("%d\n",dist[j]);
            if(dist[j]<w)
            {
                u=j;
                w=dist[j];
            }
        }
        //if(k==11) printf("%d %d %d\n",cnt,i,u);
        if(u==-1) return inf;
        sum_m+=w;
        sum_n+=pe[u];
        //if(k==11) printf("%d %d\n",sum_m,sum_n);
        vis[u]=1;
        for(j=0; j<n; j++)
        {
            if(vis[j]==1) continue;
            if(((1<<j)&k)==0) continue;
            dist[j]=min(dist[j],g[u][j]);
        }
    }
    //printf("%d %d %d %.2f\n",k,sum_n,sum_m,sum_m*1.0/sum_n);
    return sum_m*1.0/sum_n;
}

int main()
{
    int i,j,u,v,maxn,st;
    double ans;
    while(~scanf("%d%d",&n,&m))
    {
        if(n==0&&m==0) break;
        for(i=0; i<n; i++)
            scanf("%d",&pe[i]);
        for(i=0; i<n; i++)
        {
            for(j=0; j<n; j++)
            {
                scanf("%d",&g[i][j]);
            }
        }
        maxn=1<<n;
        memset(use,0,sizeof(use));
        ans=inf;
        for(i=1; i<maxn; i++)
        {
            double tp=prim(i);
            //printf("%.2f %.2f\n",ans,tp);
            if(tp-ans<-(1e-8))
            {
                ans=tp;
                st=i;
                //printf(" %f %d\n",ans,st);
            }
            use[i]=1;
        }
        int flag=0;
        //printf("%d\n",st);
        for(i=0; i<n; i++)
        {
            if(((1<<i)&st)==0) continue;
            if(flag) printf(" ");
            else flag++;
            printf("%d",i+1);
        }
        printf("\n");
    }
    return 0;
}

你可能感兴趣的:(hdu 2489 Minimal Ratio Tree 最小生成树+状态压缩)