POJ 4045 power station

本文介绍了一种算法,用于解决沿海城市遭受海啸破坏后如何最小化重建电网过程中的总热能损失的问题。通过树形DP算法,实现了计算不同社区作为电站位置时的最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

POWER STATION

Problem B. Power Station
Description
The  massive  tsunami  that  struck  the  coastal  city  has washed  away  many  of
inhabitants  and  facilities  there. After  the  tsunami, the  power  supply  facilities of the
coastal  city are completely  destroyed.  People  are  in  panic  in  the  dark  night. Doubts
remain over whether the communities will be able to rebuild the city. To calm people
down, the heads of the city are planning to rebuild the city to start with the recovery
of the power supply facilities.
The coastal city consists of n communities which are numbered  from 1 to n. To
save  the  electric  cables, n-1 cables  has  been  used  to  connect  these communities
together,  so  that  each  pair  of  communities  is  able  to  transfer  electronic  energy
mutually.   
The  heads  of  the  city  decide  to  set  a  power  station  in  one  of  the  communities.
There is thermal energy loss along the cables. Each cable has a resistance of R ohm.
The total thermal energy loss is the sum of I
2
Ri
. Here Ri
 is the total residence  along
the  path  between the i
th
 community  and  the  power  station,  and I is  a  constant. They
are troubling their head on the issue of where to set the power station to make the total
thermal energy loss minimized.
Input
There are multiple test cases.
The first line contains one integer indicating the number of test cases.
For  each  test  case,  the  first  line  contains  three  positive  integers n, I and R,
indicating  the  number  of  communities,  the  above  mentioned  constant  and  the
residence of each cable. (3 ≤ n ≤ 50000, 1 ≤ I ≤ 10, 1 ≤ R ≤ 50)
The next n-1 lines, each describe a cable connection by two integers X, Y, which
indicates that between community X and community Y, there is a cable.
Output
For each test case, please output two lines.
The first line is the minimum total thermal energy loss.
The second line is all the optional communities in ascending order.
You are requested to leave a blank line after each test case.
Sample Input
2
5 1 1
3 2
1 2
5 2
4 3
6 1 2
1 2
2 3
3 4
2 6
3 5
Sample Output
5
2
 
14
2 3

树形dp。这一题之前没有做,在金华比赛的时候没能搞出来(我真是太水了。。), 过了这么久还惦记着这个题,今天又拿出来好好做了一下,终于AC了。保存两个数组dp[]与node[]分别记录对应节点到所有子节点的距离与包括该节点在内的所有子节点的个数。用两次dfs,第一次dfs以任意一个节点做为所有节点的根节点,计算出每个点的dp[] 与node[] ,然后对应的关系为dp[x] = sum(dp[y] + node[y]) 其中y为x的子节点,node[x] = sum(node[y])。第二次搜索以第一次的根节点为根节点,计算出以每个点为根节点对应的dp[] ,计算dp[y] = dp[x] + n - 2 * node[y] ,n为节点的总数。转换很简单推一下即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>

using namespace std ;

#define MAXN 50010
vector<int> G[MAXN] ;
bool visit[MAXN] ;

long long dp[MAXN] ;//用于记录当前节点当其所有子节点的距离之和
long long node[MAXN] ; //用于记录当前节点的子节点的个数

int I ;
int R ;
int n ;

void read(){
    scanf("%d%d%d" , &n , &I , &R) ;

    for(int i = 1 ; i <= n ; i++)
        G[i].clear() ;

    int x ;
    int y ;

    int i = n - 1 ;

    while(i--){
        scanf("%d %d" , &x, &y) ;
        G[x].push_back(y) ;
        G[y].push_back(x) ;
    }
}

void dfs(int x){

    int len = G[x].size() ;

    visit[x] = 1 ;
    node[x] ++ ;
    for(int i = 0 ; i < len ; i ++){
        int j = G[x][i] ;

        if(!visit[ j ]){
            dfs( j ) ;
            dp[x] += dp[j] + node[j] ;
            node[x] += node[j] ;
        }
    }

    return ;
}

void dfs2(int x){

    int len = G[x].size() ;
    visit[x] = 1 ;

    for(int i = 0 ; i < len ; i ++){
        int y = G[x][i] ;

        if(!visit[y]){
            dp[y] = dp[x] + n - 2 * node[y] ;
            dfs2(y) ;
        }
    }
}
void solve(){

    memset(dp , 0 , sizeof(dp) ) ;
    memset(node , 0 , sizeof(node) ) ;

    memset(visit , 0 , sizeof(visit)) ;
    dfs(1)  ;
    memset(visit , 0 , sizeof(visit)) ;
    dfs2(1) ;

    int nIndex ;
    nIndex = 1 ;
    bool flag = 0 ;

    for(int i = 2 ; i <= n ; i ++){
        if(dp[nIndex] > dp[i]){
            nIndex = i ;
            flag = 0 ;
        }
        if(dp[nIndex] == dp[i])
            flag = 1 ;
    }
    printf("%I64d\n" , dp[nIndex] * I * I * R) ;

    printf("%d" , nIndex) ;

    if(flag){
        for(int i = 1 ; i <= n ; i ++){
            if(dp[nIndex] == dp[i] && nIndex != i){
                printf(" %d" , i) ;
            }
        }
    }
    printf("\n") ;
}

int main(){
    int t ;
    bool flag   ;
    flag = false ;
    scanf("%d" , &t) ;

    while(t--){
        if(flag)
            printf("\n") ;
        read()  ;
        solve() ;
        flag = true ;
    }
    return 0 ;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值