Qin Shi Huang’s National Road System HDU - 4081
题意:
出N个点的坐标以及每个点的人口, 要求将这N个点通过N-1条边连接起来, 权值为两点直接距离, B为距离和, 同时可以选中一条边, 使得该边权值变为0, A为该边两点人口数量. 求A/B的最大值
思路:
题目要求A / B最大,A是相邻两座城市的总人口数,B是除该相邻城市之间权值的最短路,遍历所有两两座城市相邻的情况(A / B)取max即可,A很好得到,两个for循环就可遍历所有两两相邻的城市总人数情况,主要是B的值,B的值可以用次短路的思想求解。
dalao的code:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <stdlib.h>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
using namespace std;
#define ms(x, n) memset(x,n,sizeof(x));
typedef long long LL;
const int inf = 1 << 30;
const LL maxn = 1010;
int N;
double w[maxn][maxn];
struct node {
int x, y;
int p;
node(int xx, int yy, int pp) {x = xx, y = yy, p = pp;}
node() {}
} vs[maxn];
double getDis(int x1, int y1, int x2, int y2) {
return sqrt((double)(x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2));
}
double d[maxn];
bool used[maxn];
double maxD[maxn][maxn]; //MST中从i->j的最大权值
int pre[maxn]; //某一点父节点
bool mst[maxn][maxn]; //该点是否已经在MST中
typedef pair<int, int> P;
double Prim(int s) {
fill(d, d + maxn, inf);
fill(pre, pre+maxn, s);
ms(maxD, 0); ms(used, 0); ms(mst, 0);
priority_queue<P, vector<P>, greater<P> > q;
q.push(P(d[s] = 0, s));
double res = 0;
while(!q.empty()) {
P cur = q.top();
q.pop();
int u = cur.second;
if(used[u])
continue;
used[u] = true, res += d[u];
mst[u][pre[u]] = mst[pre[u]][u] = true; //加入到MST中
for(int v = 1; v <= N; ++v) {
if(used[v] && w[u][v] < inf) //只更新MST中的
maxD[u][v] = maxD[v][u] = max(maxD[pre[u]][v], d[u]);
if(w[u][v] < d[v]) {
d[v] = w[u][v];
pre[v] = u; //更新父节点
q.push(P(d[v], v));
}
}
}
return res;
}
int main() {
int T, a, b, c;
scanf("%d",&T);
while(T--) {
ms(vs, 0); fill(w[0], w[0]+maxn*maxn, inf);
scanf("%d",&N);
for(int i = 1; i <= N; ++i) {
scanf("%d%d%d",&a,&b,&c);
vs[i] = node(a, b, c);
}
for(int i = 1; i < N; ++i)
for(int j = i+1; j <= N; ++j)
w[i][j] = w[j][i] = getDis(vs[i].x, vs[i].y, vs[j].x, vs[j].y);
//枚举删边, 找出最大值
double B = Prim(1), A, ans = -1;
for(int i = 1; i < N; ++i)
for(int j = i+1; j <= N; ++j){
A = vs[i].p+vs[j].p;
//这条边未在MST中使用, 尝试加边并删去生成环中的最长边, 已使用则直接变0
if(mst[i][j]){
ans = max(ans, A/(B-w[i][j]));
}else{
ans = max(ans, A/(B-maxD[i][j]));
}
}
printf("%.2lf\n", ans);
}
return 0;
}
我的sb code:
bug一下找不出,暂时懒得找了
#include<algorithm>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
using namespace std;
const int maxn = 1e3 + 5;
double mp[maxn][maxn], maxd[maxn][maxn], d[maxn];
int pre[maxn];
bool vis[maxn], opt[maxn][maxn];
struct point_city{
double x, y, w;
}city[maxn];
double prim(int n){
memset(opt, 0, sizeof(opt));
memset(vis, 0, sizeof(vis));
memset(maxd, 0, sizeof(maxd));
memset(opt, 0, sizeof(opt));
for(int i = 1; i <= n; i++)
d[i] = mp[1][i], pre[i] = 1;
vis[1] = 1;
int p;
double ans = 0;
for(int i = 1; i < n; i++){
p = -1;
for(int j = 1; j <= n; j++)
if(!vis[j] && (p == -1 || d[p] >d[j])) p = j;
vis[p] = 1;
if(p == -1) break;
ans += d[p];
for(int j = 1; j<= n; j++){
if(vis[j]) {
maxd[j][p] = maxd[p][j] = max(maxd[j][pre[p]],mp[pre[p]][p]);
opt[j][p] = opt[p][j] = 1;
opt[p][pre[p]] = opt[pre[p]][p] = 0;
}
if(d[j] > mp[p][j]) d[j] = mp[p][j], pre[j] = p;
}
}
return ans;
}
int main()
{
int t, n, x, y, w;
int cot;
scanf("%d", &t);
while(t--){
cot = 0;
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%lf%lf%lf", &city[i].x, &city[i].y, &city[i].w);
memset(mp, 0x3f, sizeof(mp));
for(int i = 1; i <= n; i++)
for(int j = i + 1; j <= n; j++){
double res = sqrt((city[i].x - city[j].x) * (city[i].x - city[j].x) +
(city[i].y - city[j].y) * (city[i].y - city[j].y));
mp[i][j] = mp[j][i] = res;
}
double res = prim(n);
double sum = 0;
for(int i = 1; i <= n; i++)
for(int j = i + 1; j <= n; j++){
if(opt[i][j]) sum = max(sum, (city[i].w + city[j].w) / (res - maxd[i][j]));
else sum = max(sum, (city[i].w + city[j].w) / (res - mp[i][j]));
}
printf("%.2lf\n", sum);
}
}