1002. [WZOI2011 S3] 周年纪念日

来源:互联网 发布:ubuntu apt 安装jdk 编辑:程序博客网 时间:2024/04/30 16:52
                                            1002. [WZOI2011 S3] 周年纪念日

Problem 3 周年纪念日

 (anniversary.pas/c/cpp)



背景

WZland即将迎来一个举国欢庆的日子—建国150亿周年纪念日,值此之际WZland有许多事情要准备……

问题描述

WZland的国王决定举办一个晚会,这次晚会要求所有的WZland居民都参加,但是他发现WZland的所有城市之间的道路都已经毁坏(平时WZland的居民都在自己的城市里活动,所以他们对于那些道路一点都不关心)。这是一件十分麻烦的事情,因为这个晚会要求所有居民都来参加,于是国王决定要重建道路。
他找出了WZland的地图,他发现WZland有N个城市,有M条破败的双向道路连接着这N个城市。由于周年纪念日就要到来,为了节省时间国王决定修建的道路恰好将这N个城市连接起来。修建一条长度为L的道路,需要花费L个Ws(Ws是WZland的通用货币),国王想要将总的花费降到最少,这样他能有足够多的钱来举办晚会。国王还有一个要求,因为这些道路是同时开始修建的,因此修建完这些道路的总时间等于修建完最长的那条道路的时间(你可以认为所有工人的修建速度是一样的,即一单位时间修建1单位长度的道路),国王想要总的修建时间最少。
由于要举行晚会,国王需要找到一个地点来举办晚会,这同样是一件十分麻烦的事情。因为WZland的每个人都十分懒,他们不愿意多走路(就连在这周年纪念日也不例外)。WZland的居民每走1单位长度的路就会产生1单位的不高兴度(这就是为什么他们都不愿离开自己城市的原因)。WZland的国王想要这个晚会的不高兴度尽量低(晚会的不高兴度就等于所有参加晚会的人的不高兴度的和),这就要求选取一个合适的地点来举办晚会(WZland的居民要通过即将修建好的道路,来到这个晚会举办地)。
举个例子,如果晚会在城市u举行,城市i有Pi个人,城市u和城市i的距离为D(u,i),那么这些人产生的不高兴度之和为Pi*D(u,i)。
国王把这个任务交给了你,他希望你能找出一个地点,是所有人的不高兴度之和最小。


输入格式

 

输入数据第一行包含两个整数N和M,表示WZland有N个城市,M条破坏的道路;
第2行到N+1行:第i+1行包含一个整数Pi,表示城市i的居民人数。
第N+2行到N+M+1行,每行三个整数A,B,L(1≤A,B≤N,A≠B),表示A和B之间有一条长度为L的破坏道路。

注意:两个城市之间可能会有多条道路。

 

输出格式

 

输出数据包含两行。
第一行两个整数C,T(用一个空格隔开),表示修建道路的最少花费和最少时间。
第二行两个整数U,H(用一个空格隔开),表示晚会的地点(如果有多个地点满足条件,输出编号最小的那个城市)和相应地点所有人的不高兴度之和。


样例输入输出

 

anniversary.in 
5 7
3
2
2
1
4
1 5 1
1 3 7
2 1 4
2 3 6
3 4 5
2 4 3
5 4 2


anniversary.out
11 5
5 29


样例解释

合法的修建方案如下图(相邻城市之间的距离和每个城市的人数见样例):

 

对题第一问 毫无疑问用kurskal就可以了 

1e6的数据 prim是不行的 

对于第二问 把最小生成树分离出来跑 树形dp 

显然不能每个点都跑一次 

我们需要从已知的点去更新其他的点  

所以先从1跑一次dp

son数组 记录 他每个子树有多少节点

d数组记录当前节点的所有子树的节点 跑到这个节点的不高兴值 

rout数组记录 从他父亲节点跑到这个节点的长度 

dp数组 记录以每个节点为根的不高兴值 

 

例如样例 假设我们已经更新到了dp[5] 

拿下一个就是 dp[4] 

dp[5]=people[1]*rout[5]+people[2]*rout[2]+people[3]*rout[3]+(peolpe[2]+people[3]+people[4])*rout[4];

dp[4]=people[1]*rout[5]+people[2]*rout[2]+people[3]*rout[3]+(people[1]+people[5])*rout[4];

显然 两个式子是有重叠部分的 

我们可以看出 当前节点的不高兴值等于

它父亲节点的不高兴值减去当前节点son值到他父亲节点的路径 

再加上剩余人数乘上从父亲节点到当前节点的路径 

 

  1 #include <cstdio>  2 #include <cctype>  3 #include <algorithm>  4   5 typedef long long LL;  6   7 const LL INF=1e18*5;  8 const int MAXN=100010;  9  10 int n,m; 11  12 int people[MAXN],fa[MAXN]; 13  14 LL total; 15  16 LL d[MAXN],dp[MAXN],son[MAXN],rout[MAXN]; 17  18 struct edge { 19     int x,y; 20     int val; 21     friend bool operator < (edge a,edge b) { 22         return a.val<b.val; 23     } 24 }; 25 edge e[MAXN<<1]; 26  27 struct node { 28     int to; 29     int next; 30     int val; 31     node() {} 32     node(int to,int val,int next):to(to),val(val),next(next) {} 33 }; 34 node Edge[MAXN<<1]; 35  36 int head[MAXN],tot; 37  38 inline void read(int&x) { 39     int f=1;register char c=getchar(); 40     for(x=0;!isdigit(c);c=='-'&&(f=-1),c=getchar()); 41     for(;isdigit(c);x=x*10+c-48,c=getchar()); 42     x=x*f; 43 } 44  45 inline void add(int x,int y,int val) { 46     Edge[++tot]=node(y,val,head[x]); 47     head[x]=tot; 48     Edge[++tot]=node(x,val,head[y]); 49     head[y]=tot; 50 } 51  52 inline int find(int x) { 53     if(x==fa[x]) return x; 54     return fa[x]=find(fa[x]); 55 } 56  57 inline void kurskal() { 58     int cnt=0,mx=-1; 59     LL sum=0; 60     for(int i=1;i<=m;++i) { 61         int xx=find(e[i].x); 62         int yy=find(e[i].y); 63         if(xx!=yy) { 64             add(e[i].x,e[i].y,e[i].val); 65             fa[xx]=yy; 66             sum+=(LL)e[i].val; 67             if(e[i].val>mx) mx=e[i].val; 68             ++cnt; 69             if(cnt==n-1) break; 70         } 71     } 72     printf("%lld ",sum); 73     printf("%d\n",mx); 74     return; 75 } 76  77 void DP(int now,int f) { 78     son[now]=people[now]; 79     for(int i=head[now];i;i=Edge[i].next) { 80         int v=Edge[i].to; 81         if(v==f) continue; 82         DP(v,now); 83         son[now]+=son[v]; 84         rout[v]=Edge[i].val; 85         d[now]+=(LL)(d[v]+(LL)son[v]*rout[v]); 86     } 87 } 88  89 void DP2(int now,int f) { 90     dp[now]=dp[f]-(LL)(son[now]*rout[now])+(LL)((total-son[now])*rout[now]); 91     for(int i=head[now];i;i=Edge[i].next) { 92         int v=Edge[i].to; 93         if(v==f) continue; 94         DP2(v,now); 95     } 96 } 97  98 int hh() { 99     freopen("anniversary.in","r",stdin);100     freopen("anniversary.out","w",stdout);101     read(n);read(m);102     for(int i=1;i<=n;++i) fa[i]=i,read(people[i]),total+=people[i];103     for(int i=1;i<=m;++i) read(e[i].x),read(e[i].y),read(e[i].val);104     std::sort(e+1,e+1+m);105     kurskal();106     DP(1,0);107     dp[1]=d[1];108     for(int i=head[1];i;i=Edge[i].next) {109         int v=Edge[i].to;110         DP2(v,1);111     }112     LL ans=INF;113     int pos;114     for(int i=1;i<=n;++i) 115       if(dp[i]<ans) ans=dp[i],pos=i;116     printf("%d %lld\n",pos,ans);117     return 0;118 }119 120 int sb=hh();121 int main(int argc,char**argv) {;}
代码

 

原创粉丝点击