1002. [WZOI2011 S3] 周年纪念日
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值到他父亲节点的路径
再加上剩余人数乘上从父亲节点到当前节点的路径
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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) {;}
作者:乌鸦坐飞机
出处:http://www.cnblogs.com/whistle13326/
新的风暴已经出现
怎么能够停止不前
穿越时空 竭尽全力
我会来到你身边
微笑面对危险
梦想成真不会遥远
鼓起勇气 坚定向前
奇迹一定会出现