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

时间:2023-10-01 22:41:02

Description

For a tree, which nodes and edges are all weighted, the ratio of it is calculated according to the following equation. HDU 2489 Minimal Ratio Tree(暴力+最小生成树)(2008 Asia Regional Beijing)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):

 #include <cstdio>
#include <cstring>
#include <iostream>
using namespace std; const int MAXN = ;
const int INF = 0x3fff3fff; int mat[MAXN][MAXN];
int weight[MAXN];
int n, m;
bool use[MAXN], vis[MAXN];
int dis[MAXN]; int prim(int st) {
memset(vis, , sizeof(vis));
vis[st] = true;
for(int i = ; i <= n; ++i) dis[i] = mat[st][i];
int ret = ;
for(int cnt = ; cnt < m; ++cnt) {
int u, min_dis = INF;
for(int i = ; i <= n; ++i)
if(use[i] && !vis[i] && dis[i] < min_dis) u = i, min_dis = dis[i];
ret += min_dis;
vis[u] = true;
for(int i = ; i <= n; ++i)
if(use[i] && !vis[i] && dis[i] > mat[u][i]) dis[i] = mat[u][i];
}
return ret;
} bool ans[MAXN];
int ans_pw, ans_ew; void dfs(int dep, int cnt, int sum_pw) {
if(cnt == m) {
int sum_ew = prim(dep - );
if(ans_ew == INF || ans_ew * sum_pw > ans_pw * sum_ew) {//ans_ew/ans_pw > sum_ew/sum_pw
for(int i = ; i <= n; ++i) ans[i] = use[i];
ans_ew = sum_ew; ans_pw = sum_pw;
}
return ;
}
if(dep == n + ) return ;
use[dep] = true;
dfs(dep + , cnt + , sum_pw + weight[dep]);
use[dep] = false;
dfs(dep + , cnt, sum_pw);
} int main() {
while(scanf("%d%d", &n, &m) != EOF) {
if(n == && m == ) break;
for(int i = ; i <= n; ++i) scanf("%d", &weight[i]);
for(int i = ; i <= n; ++i) {
for(int j = ; j <= n; ++j) scanf("%d", &mat[i][j]);
}
ans_ew = INF; ans_pw = ;
dfs(, , );
bool flag = false;
for(int i = ; i <= n; ++i) {
if(!ans[i]) continue;
if(flag) printf(" ");
else flag = true;
printf("%d", i);
}
printf("\n");
}
}