hdu 2489 Minimal Ratio Tree

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
 

 

Source
 
 
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #define inf 0x3f3f3f3f
  5 using namespace std;
  6 int n,m;
  7 int num[20];
  8 int map[20][20];
  9 int ans[20][20];
 10 int dis[20];
 11 bool mark[20];
 12 int DJ(int pm)
 13 {
 14     memset(dis,inf,sizeof(dis));
 15     memset(mark,false,sizeof(mark));
 16     for(int i=1;i<pm;i++)
 17     {
 18         dis[i]=ans[0][i];
 19     }
 20     mark[0]=true;
 21     int res=0;
 22     int temp;
 23     for(int i=1;i<pm;i++)
 24     {
 25         int Mi=inf;
 26         for(int j=0;j<pm;j++)
 27         {
 28             if(!mark[j] && dis[j]<Mi)
 29             {
 30                 Mi=dis[j];
 31                 temp=j;
 32             }
 33         }
 34         mark[temp]=true;
 35         res+=Mi;
 36         for(int j=0;j<pm;j++)
 37         {
 38            if(!mark[j] && dis[j]>ans[temp][j])
 39             {
 40                 dis[j]=ans[temp][j];
 41             }
 42         }
 43     }
 44     return res;
 45 }
 46 int main()
 47 {
 48     while(~scanf("%d%d",&n,&m))
 49     {
 50         if(n==0 && m==0)
 51         {
 52             break;
 53         }
 54         for(int i=0;i<n;i++)
 55         {
 56             scanf("%d",&num[i]);
 57         }
 58 
 59         for(int i=0;i<n;i++)
 60         {
 61             for(int j=0;j<n;j++)
 62             {
 63                 scanf("%d",&map[i][j]);
 64             }
 65         }
 66         double Minres=inf;
 67         int respos;
 68         for(int i=3;i<(1<<n);i++)
 69         {
 70             int nw=0;
 71             int len=0;
 72             int cnt=0;
 73             int res[20];
 74             memset(res,-1,sizeof(res));
 75             while(i>=(1<<len))
 76             {
 77                 if(i&(1<<len))
 78                 {
 79                     nw+=num[len];
 80                     res[cnt++]=len;
 81                 }
 82                 len++;
 83             }
 84             if(cnt!=m)
 85             {
 86                 continue;
 87             }
 88             memset(ans,inf,sizeof(ans));
 89             for(int j=0;j<cnt;j++)
 90             {
 91                 for(int k=j+1;k<cnt;k++)
 92                 {
 93                     ans[j][k]=map[res[j]][res[k]];
 94                     ans[k][j]=map[res[k]][res[j]];
 95                 }
 96             }
 97             int rr=DJ(cnt);
 98             if(rr*1.0/(nw*1.0)-Minres<-(1e-6))
 99             {
100                 Minres=rr*1.0/(nw*1.0);
101                 respos=i;
102             }
103         }
104         bool ff=false;
105         for(int i=0;i<n;i++)
106         {
107             if(respos&(1<<i))
108             {
109                 if(!ff)
110                 {
111                     ff=true;
112                     printf("%d",i+1);
113                 }
114                 else
115                 {
116                     printf(" %d",i+1);
117                 }
118             }
119         }
120         printf("\n");
121     }
122     return 0;
123 }
View Code
 
数据量的允许,使用二进制压缩的方法,枚举各种可能,每次都求一次最小生成树;
注意的地方是double 判<0( 小于0)使用高精度判断 例如判小于可以(a<b):a-b<-(1e-8)
否则会出现WA的情况
posted @ 2013-09-13 20:56  欧阳生朵  阅读(557)  评论(0编辑  收藏  举报