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.
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(" "); 68 } 69 }