HDU 4081 Qin Shi Huang's National Road System prim + (DP 或 树形DP) 好题
2012-10-07 22:30
344 查看
题意:
有n个(n<=1000)城市,告诉坐标(int),边的权值就是两点的距离,并且每个城市都有人居住,现在要修路n-1条路,使得每个城市都连通。现能让一条边可以不用任何花费。求 这条边的两端点的总人数/(包含这条边的最小生成树的总权值-这条边的权值)最大值。即(Wa+Wb)/(mst-w(a,b))最大。
思路:
先求该图的最小生成树,prim,O(n^2);
方法一: 枚举边
枚举最小生成树的每条边,去掉这条边,最小生成树变成了2个各自连通的树,假设为树A,B。分别找到树A,B中人口最多的两个点,这两个点连起来就是去掉这条边所取得的最大比例。用树形DP可以求这个最大比例。
方法二: 枚举点
在求最小生成树的过程中,预处理求出点i到点j之间在最小生成树里的最大边,用dp[i][j] 保存。枚举每两个点,求出最大值。
方法一:
处理1:
1. 用dp[i][j]表示树A中的点i 到 树B及 其子树(j点所在的树)的最大人口,这个过程可以在一边dfs就可以出来,对于每个 i 的dfs 复杂度是O(n) ,外加一个n的循环求出每个点,这里的总复杂度为 O(n^2)。
2. 通过求出来的dp[i][j] 再用一个dfs 求出 树B 到 树A的最大人口,(方法:枚举树A中的所有点 到 树B的最大人口,取其中的最小值。)显然, 这个求出来的值是我们要的去掉这条边所取得的最大比例。
代码1:
View Code
有n个(n<=1000)城市,告诉坐标(int),边的权值就是两点的距离,并且每个城市都有人居住,现在要修路n-1条路,使得每个城市都连通。现能让一条边可以不用任何花费。求 这条边的两端点的总人数/(包含这条边的最小生成树的总权值-这条边的权值)最大值。即(Wa+Wb)/(mst-w(a,b))最大。
思路:
先求该图的最小生成树,prim,O(n^2);
方法一: 枚举边
枚举最小生成树的每条边,去掉这条边,最小生成树变成了2个各自连通的树,假设为树A,B。分别找到树A,B中人口最多的两个点,这两个点连起来就是去掉这条边所取得的最大比例。用树形DP可以求这个最大比例。
方法二: 枚举点
在求最小生成树的过程中,预处理求出点i到点j之间在最小生成树里的最大边,用dp[i][j] 保存。枚举每两个点,求出最大值。
方法一:
处理1:
1. 用dp[i][j]表示树A中的点i 到 树B及 其子树(j点所在的树)的最大人口,这个过程可以在一边dfs就可以出来,对于每个 i 的dfs 复杂度是O(n) ,外加一个n的循环求出每个点,这里的总复杂度为 O(n^2)。
2. 通过求出来的dp[i][j] 再用一个dfs 求出 树B 到 树A的最大人口,(方法:枚举树A中的所有点 到 树B的最大人口,取其中的最小值。)显然, 这个求出来的值是我们要的去掉这条边所取得的最大比例。
代码1:
View Code
#include<stdio.h> #include<string.h> #include<algorithm> #include<math.h> using namespace std; #define maxn 1003 #define inf 1000000000 int x[maxn], y[maxn], p[maxn]; double map[maxn][maxn]; double dis[maxn]; int pre[maxn]; bool vis[maxn]; double mst; double dp[maxn][maxn]; double maxz(double a, double b) { return a > b ? a : b; } int n, m; double ans; double Dis(int x1, int y1, int x2, int y2) { return sqrt((x1 - x2) * (x1 - x2) * 1.0 + (y1 - y2) * (y1 - y2) * 1.0); } void prim() { int i, j, k; memset(dp, 0, sizeof(dp)); for(i = 1; i < n; i++) dis[i] = map[0][i], vis[i] = 0, pre[i] = 0; dis[0] = inf, vis[0] = 1, pre[0] = -1; mst = 0; for(i = 0; i < n-1; i++) { k = 0; for(j = 1; j < n; j++) if(!vis[j] && dis[k] > dis[j]) k = j; vis[k] = 1; mst += dis[k]; dp[pre[k]][k] = dp[k][pre[k]] = map[k][pre[k]]; for(j = 1; j < n; j++) if(!vis[j] && dis[j] > map[k][j]) dis[j] = map[k][j], pre[j] = k; for(j = 1; j < n; j++) if(vis[j] && j != k) dp[j][k] = dp[k][j] = maxz(dp[j][pre[k]], dp[pre[k]][k]); } } void solve() { int i, j; double ans = 0; for(i = 0; i < n ;i++) for(j = 0; j < n; j++) { if(i == j) continue; double tmp = (p[i] + p[j]) * 1.0/ (mst - dp[i][j]); if(tmp > ans) ans = tmp; } printf("%.2f\n", ans); } int main() { int i, j, cas; scanf("%d", &cas); while(cas--) { scanf("%d", &n); for(i = 0; i < n; i++) scanf("%d%d%d", &x[i], &y[i], &p[i]); for(i = 0; i < n; i++) for(j = 0; j < n; j++) if(i != j) map[i][j] = map[j][i] = Dis(x[i], y[i], x[j], y[j]); prim(); solve(); } return 0; }
相关文章推荐
- hdu 4081 最小生成树+树形dp
- HDU 1054 Strategic Game (树形DP)
- HDU 4313树形DP
- hdu 1011 Starship Troopers(树形DP)
- 两种解法-树形dp+二分+单调队列(或RMQ)-hdu-4123-Bob’s Race
- hdu 1561The more, The Better(树形dp&01背包)
- hdu - 3660 - Alice and Bob's Trip(树形dp)
- HDU-6201 transaction transaction transaction(树形dp)
- hdu 1054 #树形DP
- HDU 4616 Game(经典树形dp+最大权值和链)
- HDU 1520 Anniversary party 树形DP
- Hdu-5886 Tower Defence(树形DP)
- HDU 4123 Bob’s Race(树形DP+RMQ)
- hdu 2196 Computer 树形DP或者树的直径
- HDU 3586 Information Disturbing (二分+树形dp)
- hdu 4705 Y (树形dp)
- hdu 3534 树形dp
- hdu 4705(树形DP)
- HDU 1520 Anniversary party(有向边树形DP)
- hdu 1561(树形dp)(背包dp)