Problem Description
For a tree, which nodes and edges are all weighted, the ratio of it is calculated according to the following equation.
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.
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.
Input
Input contains multiple test cases. The first line of each test case contains two integers n (2<=n<=15) and m (2<=m<=n), which stands for the number of nodes in the graph and the number of nodes in the minimal ratio tree. Two zeros end the input. The next line contains n numbers which stand for the weight of each node. The following n lines contain a diagonally symmetrical n×n connectivity matrix with each element shows the weight of the edge connecting one node with another. Of course, the diagonal will be all 0, since there is no edge connecting a node with itself.
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.
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.
题意:输入n个点,要求选m个点满足连接m个点的m-1条边权值和sum与点的权值和ans最小,即sum/ans最小,并输出所选的m个点,如果有多种情况就选第一个点最小的,如果第一个点也相同就选第二个点最小的........
Output
For each test case output one line contains a sequence of the m nodes which constructs the minimal ratio tree. Nodes should be arranged in ascending order. If there are several such sequences, pick the one which has the smallest node number; if there's a tie, look at the second smallest node number, etc. Please note that the nodes are numbered from 1 .
Sample Input
3 2 30 20 10 0 6 2 6 0 3 2 3 0 2 2 1 1 0 2 2 0 0 0
Sample Output
1 3 1 2
题解
数据太小了,可以用dfs枚举组合情况再在此基础上做最小生成树,看百度上都是prim的,我就打了一个Kruskal的。可是我还太年轻,多组数据时边表忘清零了,wa了将近10次
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
int n,m,d[17],zz=0,head[17],fa[17],ansd[17],dz;
double ans;
bool pd[17];
struct bian
{int fr,to,nx,v;} e[250];
void insert(int x,int y,int z)
{zz++; e[zz].fr=x; e[zz].to=y; e[zz].v=z; e[zz].nx=head[x]; head[x]=zz;}
bool kp(const bian &x,const bian &y)
{
if(x.v<y.v) return true;
else return false;
}
int find(int x)
{
if(fa[x]!=x) fa[x]=find(fa[x]);
return fa[x];
}
double klskl()
{
int sumd=0,suml=0;
double sd,sl;
for(int i=1;i<=n;i++)
{if(pd[i])
{fa[i]=i; sumd+=d[i];}
}
for(int i=1;i<=zz;i++)
{if(pd[e[i].fr]&&pd[e[i].to])
{int r1=find(e[i].fr),r2=find(e[i].to);
if(r1!=r2)
{suml+=e[i].v; fa[r2]=r1;}
}
}
sd=sumd*1.0; sl=suml*1.0;
return sl/sd;
}
void dfs(int w,int s)
{
if(s==m)
{
double ratio=klskl();
if(ratio<ans)
{dz=0; ans=ratio;
for(int i=1;i<=n;i++)
{if(pd[i]) {dz++; ansd[dz]=i;}}
}
return ;
}
if(w>n) return;
pd[w]=true;
dfs(w+1,s+1);
pd[w]=false;
if(n-w+s>=m) dfs(w+1,s);//为了做如2,3,5,6这样的情况
}
int main()
{
while(scanf("%d%d",&n,&m)&&n&&m)
{zz=0;
for(int i=1;i<=n;i++) scanf("%d",&d[i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{int x;
scanf("%d",&x);
if(i!=j) insert(i,j,x);
}
memset(pd,false,sizeof(pd));
//memset(ansd,0,sizeof(ansd));
ans=99999999.1;
sort(e+1,e+zz+1,kp);
dfs(1,0);
int sc=0;
for(int i=1;i<=dz;i++)
{if(sc!=0) printf(" ");
printf("%d",ansd[i]); sc=1;
}
printf("\n");
}
return 0;
}