hdu 2489 Minimal Ratio Tree 最小生成树


枚举组合情况,再用最小生成树算法,我一开始半天都想不出来,最后没想到解法这么简单。

这都是因为之前对时间复杂度没有认真、正确的估计,往往简单的题目想复杂了。


因为n很小<=6,2^16也不大,prim O(n^2),这样算上去时间复杂度大概是O(2^n *n^2),到了10^7级,还是可以过的,实际上只用了15ms。



/**==========================================
 *   This is a solution for ACM/ICPC problem
 *
 *   @source:hdu 2489 Minimal Ratio Tree
 *   @type:  最小生成树
 *   @author: wust_ysk
 *   @blog:  http://blog.csdn.net/yskyskyer123
 *   @email: 2530094312@qq.com
 *===========================================*/
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int INF =0x3f3f3f3f;
const int maxn=15    ;
//const int maxV=12    ;
int w[maxn+3][maxn+3],a[maxn+3] ;
int n,m;double ans;
bool done[maxn+3];
vector<int >ve;
vector<int >ansve;
int dp[maxn+3];

void work()
{
    int fm=0;
   for(int i=0;i<ve.size();i++)
   {
       fm+=a[ ve[i] ];
   }



   memset(done,0,sizeof done);
   memset(dp,0x3f,sizeof dp);
   double tot=0;
   int now=ve[0];
   done[now]=1;
   dp[now]=0;
   for(int i=1;i<m;i++)
   {
       int mini=INF,p;
        for(int j=0;j<ve.size();j++)
        {
            int y=ve[j];
            if(done[y])  continue;
            dp[y]=min(dp[y],w[now][y]);
            if(dp[y]<mini)  {mini=dp[y]; p=y  ;}
        }
       tot+=dp[p];
       done[p]=1;//第一次wa因为写掉了这一步

       now=p;
   }

    tot/=fm;
   if(tot<ans)
   {
       ansve=ve;
       ans=tot;
   }

}
void dfs(int step,int tot)
{

   if(n-step+1<m-tot)  return;

   if(tot==m)
   {
       work();
       return;
   }
   ve.push_back(step);
   dfs(step+1,tot+1);

    ve.pop_back();
   dfs(step+1,tot);



}

void print()
{
    for(int i=0;i<ansve.size();i++)
    {
        if(i)  putchar(' ');
        printf("%d",ansve[i]);
    }
    putchar('\n');
}
int main()
{
    while(~scanf("%d%d",&n,&m)&&(n||m))
    {
        for(int i=1;i<=n;i++)  scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                scanf("%d",&w[i][j]);
            }
        }
        ve.clear();
        ans=INF;
        dfs( 1,0);
        print();


    }

   return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值