HDU 2489 Minimal Ratio Tree(暴力+最小生成树)(2008 Asia Regional Beijing)

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 .

 

题目大意:给n个点,一个完全图,要求你选出m个点和m-1条边组成一棵树,其中sum(边权)/sum(点权)最小,并且字典序最小,输出这m个点。

思路:大水题,n个选m个,$C_{n}^{m}$最大也不到1W,最小生成树算法也才$O(n^2)$,果断暴力。暴力枚举选和不选,然后用最小生成树求sum(边权),逐个比较即可。

PS:太久没写最小生成树结果混入了最短路的东西结果WA了>_<

 

代码(15MS):

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 using namespace std;
 5 
 6 const int MAXN = 18;
 7 const int INF = 0x3fff3fff;
 8 
 9 int mat[MAXN][MAXN];
10 int weight[MAXN];
11 int n, m;
12 bool use[MAXN], vis[MAXN];
13 int dis[MAXN];
14 
15 int prim(int st) {
16     memset(vis, 0, sizeof(vis));
17     vis[st] = true;
18     for(int i = 1; i <= n; ++i) dis[i] = mat[st][i];
19     int ret = 0;
20     for(int cnt = 1; cnt < m; ++cnt) {
21         int u, min_dis = INF;
22         for(int i = 1; i <= n; ++i)
23             if(use[i] && !vis[i] && dis[i] < min_dis) u = i, min_dis = dis[i];
24         ret += min_dis;
25         vis[u] = true;
26         for(int i = 1; i <= n; ++i)
27             if(use[i] && !vis[i] && dis[i] > mat[u][i]) dis[i] = mat[u][i];
28     }
29     return ret;
30 }
31 
32 bool ans[MAXN];
33 int ans_pw, ans_ew;
34 
35 void dfs(int dep, int cnt, int sum_pw) {
36     if(cnt == m) {
37         int sum_ew = prim(dep - 1);
38         if(ans_ew == INF || ans_ew * sum_pw > ans_pw * sum_ew) {//ans_ew/ans_pw > sum_ew/sum_pw
39             for(int i = 1; i <= n; ++i) ans[i] = use[i];
40             ans_ew = sum_ew; ans_pw = sum_pw;
41         }
42         return ;
43     }
44     if(dep == n + 1) return ;
45     use[dep] = true;
46     dfs(dep + 1, cnt + 1, sum_pw + weight[dep]);
47     use[dep] = false;
48     dfs(dep + 1, cnt, sum_pw);
49 }
50 
51 int main() {
52     while(scanf("%d%d", &n, &m) != EOF) {
53         if(n == 0 && m == 0) break;
54         for(int i = 1; i <= n; ++i) scanf("%d", &weight[i]);
55         for(int i = 1; i <= n; ++i) {
56             for(int j = 1; j <= n; ++j) scanf("%d", &mat[i][j]);
57         }
58         ans_ew = INF; ans_pw = 1;
59         dfs(1, 0, 0);
60         bool flag = false;
61         for(int i = 1; i <= n; ++i) {
62             if(!ans[i]) continue;
63             if(flag) printf(" ");
64             else flag = true;
65             printf("%d", i);
66         }
67         printf("\n");
68     }
69 }
View Code

 

posted @ 2013-08-14 20:33  Oyking  阅读(340)  评论(0编辑  收藏  举报