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.  
HDU 2489 Minimal Ratio Tree(暴力+最小生成树)(2008 Asia Regional Beijing)
 

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

 

你可能感兴趣的:(最小生成树)