// hdoj 2489-Minimal Ratio Tree /* * 组合序列+最小生成树 * 将全组合函数修改部分即可 * 生成所有节点数为m的组合序列,分别调用prim,不断更新ratio值 * !!!ratio值初始化放递归函数外 * 题目来源:2008 Asia Regional Beijing * wa ac 15ms 292k */ #include <iostream> #include <stdio.h> #include <string.h> using namespace std; #define MAX_N 20 #define inf 0xfffffff int n,mm; int rcd[MAX_N],map[MAX_N][MAX_N],price[MAX_N]; int tmp[MAX_N],lowc[MAX_N],vis[MAX_N]; double ratio,min1;//!!! double prim(int p[]) { int i,j,pp,minc,len=0,sum=0; memset(vis,0,sizeof(vis)); for(i=0; i<mm; ++i) lowc[p[i]]=map[p[0]][p[i]]; vis[p[0]]=1; for(i=1; i<mm; ++i){ minc=inf; pp=-1; for(j=0; j<mm; ++j){ if(!vis[p[j]]&&lowc[p[j]]<minc){ minc=lowc[p[j]]; pp=p[j]; } } vis[pp]=1; len+=lowc[pp]; for(j=0; j<mm; ++j){ if(!vis[p[j]]&&map[p[j]][pp]<lowc[p[j]]) lowc[p[j]]=map[p[j]][pp]; } } for(i=0; i<mm; ++i) sum+=price[p[i]]; return len*1.0/sum; } void full_combination(int l, int p) { int i; if(l==mm){ min1=prim(rcd); if(min1<ratio){ ratio=min1; for(i=0; i<mm; ++i) tmp[i]=rcd[i]; } } for (i=p; i<n; i++){ rcd[l] = i+1; full_combination(l+1, i+1); } } int main() { int i,j; while (scanf("%d%d", &n,&mm)&&(n!=0||mm!=0)){ for(i=1; i<=n; ++i) cin>>price[i]; for(i=1; i<=n; ++i) for(j=1; j<=n; ++j) cin>>map[i][j]; ratio=inf; full_combination(0, 0); for(i=0; i<mm; ++i) (i!=mm-1) ? cout<<tmp[i]<<' ' : cout<<tmp[i]; cout<<endl; } return 0; }