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.
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.
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
思路:
思路其实很简单,我们看到了数据不超过15,那么直接dfs搜索枚举各种node的组合情况,而对于每一种情况来说nodesum时固定的,就找到最小的edgesum就行了,这个要用prime算法生成最小生成树。
之前不会prime,大概想了一下,就是每次从已经选乐的节点中找到最短的向外延伸的边,最后把端点的另一头加到已经访问的端点里
(我自己写的代码很难看而且不太适用,最好学习一下prime的模板)
#include<stdio.h>
#include<iostream>
#include<string.h>
#define input freopen("input.txt","r",stdin)
using namespace std;
int m,n;
int value[30],v[30];
double ratio;
int key[30][30],mapv[30][30];
int writev[30];
void handle()
{
int i,j,k,use[30];
int pos=0,minn;
int edgesum=0,nodesum=0;
memset(mapv,0,sizeof(mapv));
memset(use,0,sizeof(use));
// for(i=1;i<=n;i++)
// {
// cout<<v[i]<<" ";
// }cout<<endl;
for(i=1;i<=n;i++)
{
if(v[i])
{
use[i]=1;
break;
}
}
for(k=1;k<m;k++)
{
minn=10000;
for(i=1;i<=n;i++)
{
if(use[i])
{
for(j=1;j<=n;j++)
{
if(v[j]&&!use[j]&&key[i][j]<minn)
{
pos=j;
minn=key[i][j];
}
}
}
}
use[pos]=1;
edgesum+=minn;
}
for(i=1;i<=n;i++)
{
if(v[i])
{
nodesum+=value[i];
}
}
if(edgesum*1.0/nodesum<ratio)
{
ratio=edgesum*1.0/nodesum;
for(i=1;i<=n;i++)
{
writev[i]=v[i];
}
}
}
void dfs(int pos,int time)
{
int i;
if(time<0||time>m+1)return ;
if(time==m) handle();
for(i=pos+1;i<=n;i++)
{
v[i]=1;
dfs(i,time+1);
v[i]=0;
}
}
int main()
{
input;
int i,j;
while(cin>>n>>m)
{
if(n==0&&m==0)break;
memset(writev,0,sizeof(writev));
for(i=1;i<=n;i++)
cin>>value[i];
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
cin>>key[i][j];
ratio=10000;
for(i=1;i<=n;i++)
{
v[i]=1;
dfs(i,1);
v[i]=0;
}
int flag=0;
for(i=1;i<=n;i++)
{
if(writev[i])
{
if(flag)cout<<" ";
flag=1;
cout<<i;
}
}cout<<endl;
}
return 0;
}