Minimal Ratio Tree
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 1071 | Accepted: 389 |
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
先用回溯找到所有的组合,在用最小生成树,注意返回的值是边权/点权
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
const double INF = 1e10;
const int maxn = 25;
vector<vector<int> > g;
double mat[maxn][maxn],NODE[maxn],ratio[maxn];
bool vis[maxn];
int n,m;
void input(){
g.clear();
for(int i = 1; i <= n; i++) scanf("%lf",&NODE[i]);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
scanf("%lf",&mat[i][j]);
}
void cc(vector<int> &k,int c){
if(k.size()==m){
g.push_back(k);
return;
}
for(int i = c; i <= n; i++){
k.push_back(i);
cc(k,i+1);
k.pop_back();
}
}
double prim(vector<int> &node){
int v = -1;
double mincost[maxn],ans = 0;
for(int i = 0; i < node.size(); i++){
mincost[node[i]] = INF;
vis[node[i]] = 0;
}
mincost[node[0]] = 0;
double res = 0;
for(int i = 0; i < node.size(); i++){
int v = -1;
for(int j = 0; j < node.size(); j++)
if(!vis[node[j]]){
if(v == -1) v = node[j];
else if(mincost[node[j]]<mincost[v]) v = node[j];
}
if(v == -1) break;
vis[v] = 1;
ans+=mincost[v];
for(int j = 0; j < node.size(); j++){
if(fabs(mat[v][node[j]])>1e-8){
if(!vis[node[j]]){
int x = node[j];
mincost[x] = min(mincost[x],mat[v][node[j]]);
}
}
}
}
double SN = 0;
for(int i = 0; i < node.size(); i++){
SN += NODE[node[i]];
}
return ans/SN;
}
void solve(){
vector<int> node;
cc(node,1);
node.clear();
double ans = INF;
for(int i = 0; i < g.size(); i++){
double tmp = prim(g[i]);
if(ans > tmp){
ans = tmp;
node = g[i];
}
}
sort(node.begin(),node.end());
cout<<node[0];
for(int i = 1; i < node.size(); i++)
cout<<" "<<node[i];
cout<<endl;
}
int main(){
while(~scanf("%d%d",&n,&m)&&n+m){
input();
solve();
}
return 0;
}