hdu 3423 Subway upgrade(最小生成树+树dp)

14 篇文章 0 订阅

Subway upgrade

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 373    Accepted Submission(s): 110


Problem Description
As we all know, one of the most important inventions for modern-day public transportation is the subway, which brings much convenience to our daily-life and saves us from the congested traffic.
However, to hold the next ACM regional contest, you, as the mayor of city X, decided to upgrade the subway system of that city. There are some stations and roads in the city now, any road has a cost. To save money, you decided not to construct every road, but to make sure that there exist a path between every two stations.
Sorry, the mission isn't completed. You know, there are n stations in the city,some contestants visit other stations regularly to admire some so-called big cows. Being naturally averse to spending hours each day on commuting, you should help them to find a place to live for which the total travel time is minimal.
Every road has an ID, from 1 to m. If there are multiple approaches leading to the same minimal cost, the mayor prefers the one of which road IDs selected holds the smallest lexicographic order. For instance, rebuilding ID ( 1 3 5) and ID (2 4 5) will both ensure the minimum cost,the mayor will choose the former one.
 

Input
First,a number t,indicating the number of the testcases.
For every testcase, there is a number n and m,n(1<=n<=50000) indicating the number of cities,whereas m (0<=m<=500000) indicating the number of roads.
then m lines follow each lines contains three integers a,b,c.(1<=a,b<=n&&a!=b,1<=c<=10000)which means there is a road from a to b whose cost is c.
 

Output
First the minimum cost.If doesn't exist,only output "Poor mayor."(without quotes)
Then output the answer and all the candidate stations.
 

Sample Input
  
  
3 3 3 1 2 10 2 3 20 3 1 15 3 1 1 2 15 2 1 1 2 15
 

Sample Output
  
  
25 1 50 Poor mayor. 15 1 2 30 Hint: In the first sample we use road 1 and 3 ,the minimus cost is 10+15=25 and we get a new graph 3-1-2,city 1 is the best answer ,2*10+2*15=50 Whereas the third, we can't get city 1,2,3 connected. In the last, we choose the road 1,the minimus cost is 15 and we get a new graph 1-2,both city 1 and city 2 are the best answer ,2*15=30
 
题意:求最小生成树,并且求哪些点距离其他点距离之和最小。
思路:krasual求最小生成树,然后两次树dp求出每个点到其他点的距离之和。
 
AC代码:
#include <iostream>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <queue>
#include <ctime>
#include <vector>
#include <algorithm>
#define ll long long
#define L(rt) (rt<<1)
#define R(rt)  (rt<<1|1)
using namespace std;

const int INF = 1e9;
const int maxn = 50005;

struct Edge{
    int v, w, next;
}et[maxn * 4];
struct node{
    int u, v, l, id;
}ed[maxn * 10];
int eh[maxn], fa[maxn], son[maxn], ans[maxn];
ll dis1[maxn], dis2[maxn];
int n, m, num;
ll Min;
void init(){
    memset(eh, -1, sizeof(eh));
    for(int i = 1; i <= n; i++) fa[i] = i;
    num = 0;
}
void add(int u, int v, int w){
    Edge e = {v, w, eh[u]};
    et[num] = e;
    eh[u] = num++;
}
int find(int x){
    return x == fa[x] ? x : fa[x] = find(fa[x]);
}
bool cmp(node a, node b){
    if(a.l != b.l) return a.l < b.l;
    return a.id < b.id;
}
void dfs1(int u, int pre){
    son[u] = 1;
    dis1[u] = 0;
    for(int i = eh[u]; i != -1; i = et[i].next)
    {
        int v = et[i].v, w = et[i].w;
        if(v == pre) continue;
        dfs1(v, u);
        son[u] += son[v];
        dis1[u] += son[v] * w + dis1[v];
    }
}
void dfs2(int u, int pre, int pedge){
    if(pre == -1) dis2[u] = 0;
    else dis2[u] = dis2[pre] + dis1[pre] - dis1[u] - son[u] * pedge + ((ll)n - son[u]) * pedge;
    for(int i = eh[u]; i != -1; i = et[i].next)
    {
        int v = et[i].v, w = et[i].w;;
        if(v == pre) continue;
        dfs2(v, u, w);
    }
    if(Min > dis1[u] + dis2[u]) Min = dis1[u] + dis2[u];
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d%d", &n, &m);
        init();
        for(int i = 0; i < m; i++)
        {
            scanf("%d%d%d", &ed[i].u, &ed[i].v, &ed[i].l);
            ed[i].id = i;
        }
        sort(ed, ed + m, cmp);
        ll ans1 = 0;
        for(int i = 0; i < m; i++)
        {
            int u = ed[i].u, v = ed[i].v, l = ed[i].l;
            int ru = find(u), rv = find(v);
            if(ru == rv) continue;
            fa[ru] = rv;
            add(u, v, l);
            add(v, u, l);
            ans1 += l;
        }
        int cnt = 0;
        for(int i = 1; i <= n; i++)
        if(i == find(i)) cnt++;
        if(cnt > 1)
        {
            printf("Poor mayor.\n");
            continue;
        }
        Min = 0x7fffffffffffffffLL;
        dfs1(1, -1);
        dfs2(1, -1, 0);
        printf("%I64d\n", ans1);
        cnt = 0;
        for(int i = 1; i <= n; i++)
        if(dis1[i] + dis2[i] == Min)
        ans[cnt++] = i;
        for(int i = 0; i < cnt - 1; i++)
        printf("%d ", ans[i]);
        printf("%d\n", ans[cnt - 1]);
        printf("%I64d\n", 2 * Min);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值