题意:
给你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;
}