题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=2489
Given a complete graph of n nodes with all nodes and edges weighted, your task is to find a tree, which is a sub-graph of the original graph, with m nodes and whose ratio is the smallest among all the trees of m nodes in the graph.
All the weights of both nodes and edges (except for the ones on the diagonal of the matrix) are integers and in the range of [1, 100].
The figure below illustrates the first test case in sample input. Node 1 and Node 3 form the minimal ratio tree.
3 2 30 20 10 0 6 2 6 0 3 2 3 0 2 2 1 1 0 2 2 0 0 0
1 3 1 2
题目大意:给出一个n个节点的完全图(n<=15),每个边都有权值,每个点也都有权值,求一个有m个节点的树,使得该树的边权值和和点权值和是所有m个节点的树中最小的。如果有多种解,则输出将节点编号从小到大排序后,字典序最小的那个解
思路:n很小,故可以直接枚举可能C(n,m)中m个点的情况,对m个点求其最小生成树,记录比较比值最小的生成树的节点
程序:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int INF=10000000;
int n,m,nw[20],e[20][20],a[20],arr[20];
double ans;
bool used[20];
int prim(){
int i,j,d[20],flag[20],sum=0;
memset(flag,0,sizeof flag);
fill(d,d+20,INF);
d[a[1]]=0;
while (1){
int v=-1;
for (i=1;i<=m;i++){
if (!flag[a[i]] && (v==-1 || d[a[v]]>d[a[i]])) v=i;
}
if (v==-1) return sum;
flag[a[v]]=1;
sum+=d[a[v]];
for (i=1;i<=m;i++)
if (!flag[a[i]]) d[a[i]]=min(d[a[i]],e[a[v]][a[i]]);
}
}
void dfs(int k,int l){
int i,j;
if(n-l<m-k) return;
if (k>m){
int nw_sum=0;
for (i=1;i<=m;i++){
nw_sum+=nw[a[i]];
}
int ew_sum=prim();
if (abs(ans-ew_sum*1.0/nw_sum)>=0.00000008&&ans>ew_sum*1.0/nw_sum){
ans=ew_sum*1.0/nw_sum;
for (i=1;i<=m;i++)
arr[i]=a[i];
}
return;
}
for (i=l;i<=n;i++){
if (!used[i]){
used[i]=true;
a[k]=i;
dfs(k+1,i);
used[i]=false;
}
}
}
int main(){
int i,j;
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
while (scanf("%d%d",&n,&m)==2 &&(n+m)>0){
ans=INF;
for (i=1;i<=n;i++)
scanf("%d",&nw[i]);
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
scanf("%d",&e[i][j]);
memset(used,0,sizeof used);
dfs(1,1);
for (i=1;i<m;i++)
printf("%d ",arr[i]);
printf("%d\n",arr[m]);
}
return 0;
}