hdu2489(prim+dfs)

题意:

      给你n个点,和任意两点的距离,让你在这N个点中找到一个有m个点并且ratio最小的树.
                        ratio = sum(edge) / sum(node)


虽然用暴力做的,时间限制还蛮大。。

把每m个点用dfs列出来(注意这个dfs必须写的足够精简,每种情况只出现一次,不然会超时)

然后最小树找最短边之和

比较ratio


T_T


#include <iostream>

#include <stdio.h>

#include <string.h>

#include <math.h>

#include <algorithm>

using namespace std;

int n,m;

int node[16];

int tu[20][20],s[28],ans[16];

int lowcost[28];

int nsum,esum;

double old;

void prim(int fi)

{

    int u;

    esum=0;

    for(int j=1;j<=n;j++)

        lowcost[j]=tu[fi][j];

    s[fi]=2;

    for(int i=1;i<=n;i++)

    {

        int minn=105;

        for(int j=1;j<=n;j++)

        {

            if(s[j]==0&&minn>lowcost[j])

            {

                minn=lowcost[j];

                u=j;

            }

        }

        

        if(minn==105)

            return;

        s[u]=2;

        esum+=minn;

        for(int j=1;j<=n;j++)

        {

            if(lowcost[j]>tu[u][j]&&s[j]==0)

                lowcost[j]=tu[u][j];

        }

    }

    return ;

}

void dfs(int num,int d)

{

    if(num==m)

    {

        prim(d);

        if(esum<old*nsum)

        {

            old=esum/(nsum*1.0);

            int k=0;

            for(int i=1;i<=n;i++)

            {

                if(s[i]==2)

                {

                    s[i]=0;

                    ans[k++]=i;

                }

            }

        }

        for(int i=1;i<=n;i++)

        {

            if(s[i]==2)

            {

                s[i]=0;

            }

        }

        return;

    }

    int j;

    for(j=d+1;j<=num+1+n-m;j++)

    {

        if(s[j]==-1)

        {

            s[j]=0;

            nsum+=node[j];

            dfs(num+1,j);

            s[j]=-1;

            nsum-=node[j];

        }

    }

    return;

}

int main()

{

    while(scanf("%d %d",&n,&m))

    {

        if(n==0&&m==0)

            break;

        for(int i=1;i<=n;i++)

            scanf("%d",&node[i]);

        

        for(int i=1;i<=n;i++)

        {

            for(int j=1;j<=n;j++)

            {

                scanf("%d",&tu[i][j]);

                if(i!=j)

                    tu[j][i]=tu[i][j];

                else

                    tu[i][j]=tu[j][i]=105;

            }

        }

        nsum=0;

        esum=0;

        old=1005;

        memset(s,-1,sizeof(s));

        dfs(0,0);

        for(int i=0;i<m-1;i++)

            printf("%d ",ans[i]);

        printf("%d\n",ans[m-1]);

    }

    return 0;

}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值