枚举组合情况,再用最小生成树算法,我一开始半天都想不出来,最后没想到解法这么简单。
这都是因为之前对时间复杂度没有认真、正确的估计,往往简单的题目想复杂了。
因为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;
}