Qin Shi Huang's National Road System 【HDU - 4081】【次优比例生成树(最优比例生成树变形)】

题目链接


  题目问的是有N个点集,问你建立N-1条边的情况下,使得路径最短的方案数,但是呢,题目中又给出徐福会魔法可以把一条路径变成免费道路,但是有个限制就是希望这条路上两个城市的人口数比上除去该路径以外整棵树的权值能最大。

  一开始就想到的是最优比例生成树,但是却有很多地方不大对,没法往下推下去,强行过了样例交了两发最后草草WA了,后来画了张图去推了下,发现了件事,我们看到样例一所给出的结论,样例一的图我们先按最优比例生成树来写,然后我们去遍历O(N^2)的边集,去寻最优比例生成树上的边上的两端点的人数和比上除去这条边以外的整棵树的权重,发现答案是60.00,而非65.00,造成这样的原因就在于我们需要再建的魔法边不是人数“20”->“100”的那条边,而是“30”->“100”的那条边那么意味着我们还需要考虑这样的可能,那么需要怎么做?

  我们在建树的时候还需要考虑成环的可能了。就是说假如两条边不是树上的边,但是有可能这两点建立的边会成为最后的答案边,就如同样例一,所以,我们考虑加上这条边之后成环后除该边以外环内的其他边中路径最长的,因为我们只需要用树的权重剪去这条最长边的路径也一样是树。

  就是怎样处理环是个题目,这里的思想有点类似dp但又有少许区别,就是我们遇到前面已经放进prime树中的点,说明这两点肯定就不能构成边,而且会使得之前的边在一起构成环,所以,怎么解?我们要去找到这两点之间的最长边的权值,可以通过找之前状态的以及前一条边的大小,因为目前节点pos的pre[pos]就是指的前一个状态下的,而前一刻状态唯独不包括的就是目前存进prime中的边,所以比较下哪个大,就可以往后走了。


#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxN=1005;
int N;
struct node
{
    int x, y, person;
    node(int a=0, int b=0, int c=0):x(a), y(b), person(c) {}
}a[maxN];
double Dist(node e1, node e2) { return 1.*sqrt( 1.*(e1.x-e2.x)*(e1.x-e2.x) + 1.*(e1.y-e2.y)*(e1.y-e2.y) ); }
double edge[maxN][maxN], path[maxN][maxN], lowercost[maxN];
bool used[maxN][maxN];
double Prime(int pos)
{
    memset(path, 0, sizeof(path));
    memset(used, false, sizeof(used));
    double ans=0;
    bool vis[maxN]; memset(vis, false, sizeof(vis));
    int pre[maxN];
    pre[pos]=0;
    for(int i=1; i<=N; i++) if(i!=pos) { lowercost[i]=edge[pos][i]; pre[i]=pos; }
    vis[pos]=true;
    for(int line=1; line<N; line++)
    {
        double minn = INF;
        for(int i=1; i<=N; i++)
        {
            if(!vis[i] && minn>lowercost[i]) { minn=lowercost[i]; pos=i; }
        }
        vis[pos]=true;
        ans+=minn;
        used[pos][pre[pos]] = used[pre[pos]][pos] = true;
        for(int i=1; i<=N; i++)
        {
            if(vis[i] && i!=pos) path[i][pos] = path[pos][i] = max(minn, path[i][pre[pos]]);
            if(!vis[i] && lowercost[i]>edge[pos][i])
            {
                lowercost[i] = edge[pos][i];
                pre[i] = pos;
            }
        }
    }
    return ans;
}
int main()
{
    int T;  scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &N);
        for(int i=1; i<=N; i++) scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].person);
        for(int i=1; i<=N; i++) for(int j=i+1; j<=N; j++) edge[i][j] = edge[j][i] = Dist(a[i], a[j]);
        double minn_Tree=Prime(1), ans=0;
        for(int i=1; i<=N; i++)
        {
            for(int j=i+1; j<=N; j++)
            {
                if(used[i][j]) ans=max(ans, 1.*(a[i].person+a[j].person)/(minn_Tree-edge[i][j]));
                else ans=max(ans, 1.*(a[i].person+a[j].person)/(minn_Tree-path[i][j]));
            }
        }
        printf("%.2lf\n", ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41730082/article/details/83714085