Minimal Ratio Tree
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3057 Accepted Submission(s): 917
Total Submission(s): 3057 Accepted Submission(s): 917
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.
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
Source
枚举n个顶点中所有个m个顶点的最小生成树,选出一个比率最小的即可Prim算法。注意至少要深搜1-——n-m+1个结点,才能确保遍历所有组合
#include<iostream>
#include<string.h>
using namespace std;
const int INF=0x1f1f1f1f;
int edge[20][20];
int node[20];
bool flag[20];
bool f1[20];
double res;
int dfs_cnt;
bool arr[20];
int n,m;
int mst()
{
int ret=0;
int low[20]={0};
int sta;
for(int i=1;i<=n;i++)
{
if(f1[i])
{
sta=i;
break;
}
}
low[sta]=0;
flag[sta]=1;
for(int i=1;i<=n;i++)
{
if(f1[i])
{
low[i]=edge[sta][i];
}
}
for(int i=1;i<m;i++)
{
int Min=INF;
int loc;
for(int j=1;j<=n;j++)
{
if(f1[j]&&!flag[j]&&low[j]<Min)
{
Min=low[j];
loc=j;
}
}
flag[loc]=1;
ret+=low[loc];
for(int j=1;j<=n;j++)
{
if(f1[j]&&!flag[j])
{
if(edge[loc][j]<low[j])
{
low[j]=edge[loc][j];
}
}
}
}
return ret;
}
void dfs(int v)
{
f1[v]=1;
dfs_cnt++;
if(dfs_cnt==m)
{
memset(flag,0,sizeof(flag));
int r=mst();
int sum=0;
for(int i=1;i<=n;i++)
{
if(f1[i])
{
sum+=node[i];
}
}
double ans=double(r)/double(sum);
if(ans-res<-(1e-9))
{
memcpy(arr,f1,sizeof(f1));
res=ans;
}
f1[v]=0;
dfs_cnt--;
return ;
}
for(int i=v+1;i<=n;i++)
{
dfs(i);
}
f1[v]=0;
dfs_cnt--;
}
int main()
{
while(cin>>n>>m,n+m)
{
for(int i=1;i<=n;i++)
cin>>node[i];
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
cin>>edge[i][j];
}
res=double (INF);
for(int i=1;i<=n-m+1;i++)
{
memset(f1,0,sizeof(f1));
dfs_cnt=0;
dfs(i);
}
int fir=1;
for(int i=1;i<=n;i++)
{
if(arr[i])
{
if(fir)
{
fir=0;
cout<<i;
}
else
cout<<" "<<i;
}
}
cout<<endl;
}
return 0;
}