HDU-4081 Qin Shi Huang's Road 8ystem(次小生成树)

题目链接
原标题:Qin Shi Huang’s National Road System
CSDN把System设置成非法字符?

题意

N N 个城市每个城市有一定的人口,秦始皇要修地铁了。他的手下运用魔法之后可以让一条路的代价为0,秦始皇想知道在那条路上运用魔法可以使得 \frac{这条路两端的人口总数}{修路的花费} 最大

思路
  • 修路的花费尽量小
  • 选择路两端的人口总数尽量大

先求最小生成树然后判断每条边,如果这条边是最小生成树上的边
ans = \frac{最小生数的权值和-这条边}{这条边两端人口总和} , 如果这条边不是最小生成树上的一条边,我们需要构造一个次小生成树,然后类似的求出最大值,中间不断更新 M a x Max 即可。

k r u s k a l kruskal: 218MS 32720K,空间勉强卡过, v e c t o r vector 的内存成倍扩大。。
p r i m prim: 124MS 10268K
29061190 2019-04-26 11:45:53 Accepted 4081 2420 B G++ henuyh

// prim
#include <bits/stdc++.h>
#define LL long long
#define P pair<int, int>
#define lowbit(x) (x & -x)
#define mem(a, b) memset(a, b, sizeof(a))
#define mid ((l + r) >> 1)
#define lc rt<<1
#define rc rt<<1|1
#define endl '\n'
const int maxn = 1001;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
using namespace std;
int n, m;
struct ac{
    int u, v, w;
    ac(int u_=0, int v_=0, int w_=0){
        u = u_; v = v_; w = w_;
    }
    inline int Dis(ac x) {
        return ((x.u-u)*(x.u-u) + (x.v-v)*(x.v-v));
    }
};
int g[maxn][maxn], val[maxn], vis[maxn], dis[maxn];
int pre[maxn], maxd[maxn][maxn];
bool used[maxn][maxn];
    
double Count(int i, int j, double sum) {
    return (val[i] + val[j]) * 1.0 / (sum - sqrt(g[i][j]));
}
void prim(int s) {
    mem(maxd, 0);
    mem(vis, 0);
    mem(used, 0);
    for (int i = 0; i < n; ++i) {
        dis[i] = g[s][i];
        pre[i] = s;
    }

    vis[s] = 1;
    double sum = 0;
    for (int i = 1; i < n; ++i) {
        int u = -1, MIN = inf;
        for (int j = 0; j < n; ++j) {
            if (vis[j]) continue;
            if (MIN > dis[j]) {
                MIN = dis[j];
                u = j;
            }
        }
        if (u == -1) break;
        vis[u] = 1;
        sum += sqrt(MIN);
        used[pre[u]][u] = used[u][pre[u]] = 1;
        maxd[u][pre[u]] = maxd[pre[u]][u] = MIN;
        for (int j = 0; j < n; ++j) {
            if (j == u) continue;
            if (vis[j]) {
                maxd[u][j] = maxd[j][u] = max(maxd[pre[u]][j], MIN);
            }
            if (vis[j] == 0 && dis[j] > g[u][j]) {
                dis[j] = g[u][j];
                pre[j] = u;
            }
        } 
    }
    double ans = 0;
    for (int i = 0; i < n; ++i) {
        for (int j = i + 1; j < n; ++j) {
            if (used[i][j]) ans = max(ans, Count(i, j, sum));
            else ans = max(ans, Count(i, j, sum - sqrt(maxd[i][j]) + sqrt(g[i][j])));
        }
    }
    printf("%.2lf\n", ans);
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);

    int T;
    scanf("%d", &T);
    while (T--) {
        scanf("%d", &n);
        vector<ac> t(n);
        mem(g, inf);
        for (int i = 0; i < n; ++i) {
            scanf("%d%d%d", &t[i].u, &t[i].v, &val[i]);
        }
        for (int i = 0; i < n; ++i) {
            for (int j = i+1; j < n; ++j) {
                g[i][j] = g[j][i] = t[i].Dis(t[j]);
            }
        }
        prim(0);
    }
    return 0;
}
// kruskal
#include <bits/stdc++.h>
#define LL long long
#define P pair<int, int>
#define lowbit(x) (x & -x)
#define mem(a, b) memset(a, b, sizeof(a))
#define mid ((l + r) >> 1)
#define lc rt<<1
#define rc rt<<1|1
#define endl '\n'
const int maxn = 1e3 + 1;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
using namespace std;
struct ac{
    int u, v, flag;
    double w;
    ac(int u_=0, int v_=0, double w_=0, int flag_=0){
        u = u_; v = v_; w = w_; flag = flag_;
    }
    bool operator <(ac t) {
        return w < t.w;
    }
}g[1000001];
vector<int> son[maxn];
int pre[maxn], val[maxn];
double dis[maxn][maxn];
int find (int x) {
    return (pre[x] == x) ? x : pre[x] = find(pre[x]);
}
int n, m;
double Dis(ac x, ac y) {
    return sqrt((x.u-y.u)*(x.u-y.u) + (x.v-y.v)*(x.v-y.v));
}
double Count(double all, ac t) {
    return (val[t.u] + val[t.v]) * 1.0 / (all - t.w); 
}
void Kruskal() {
    for (int i = 0; i <= n; ++i) {
        son[i].clear();
        son[i].push_back(i);
        pre[i] = i;
    }
    sort(g, g+m);
    double sum = 0;
    int cnt = 0;
    for (int i = 0; i < m; ++i) {
        if (cnt == n+1) break;
        int fx = find(g[i].u);
        int fy = find(g[i].v);
        if (fx == fy) continue;
        g[i].flag = 1;
        sum += g[i].w;
        cnt++;
        int lenx = son[fx].size();
        int leny = son[fy].size();
        if (lenx < leny) {
            swap(lenx, leny);
            swap(fx, fy);
        }
        for (int j = 0; j < lenx; ++j) {
            for (int k = 0; k < leny; ++k) {
                dis[son[fx][j]][son[fy][k]] = dis[son[fy][k]][son[fx][j]] = g[i].w; 
            }
        }
        pre[fy] = fx;
        for (int j = 0; j < leny; ++j) {
            son[fx].push_back(son[fy][j]);
        }
        son[fy].clear();
    }
    double ans = -1;
    for (int i = 0; i < m; ++i) {
        if (g[i].flag) {
            ans = max(ans, Count(sum, g[i]));
        }else {
            ans = max(ans, Count(sum + g[i].w - dis[g[i].u][g[i].v], g[i])); 
        }
    }
    printf("%.2lf\n", ans);
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);

    int T;
    scanf("%d", &T);
    while (T--) {
        scanf("%d", &n);
        vector<ac> t(n);
        for (int i = 0; i < n; ++i) {
            scanf("%d%d%d", &t[i].u, &t[i].v, &val[i]);
        }
        m = 0;
        for (int i = 0; i < n; ++i) {
            for (int j = i+1; j < n; ++j) {
                g[m++] = ac(i, j, Dis(t[i], t[j]), 0);
            }
        }
        Kruskal();
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/henuyh/article/details/89541732