1700 施工方案第二季
2012年市队选拔赛北京
时间限制: 1 s
空间限制: 128000 KB
题目等级 : 黄金 Gold
题目描述 Description
c国边防军在边境某处的阵地是由n个地堡组成的。工兵连受命来到阵地要进行两期施工。
第一期的任务是挖掘暗道让所有地堡互联互通。现已勘测设计了m条互不相交的暗道挖掘方案,如果这m条暗道都实施挖掘,肯定能达到互联互通的目的。事实上,适当选择其中n-1个方案挖掘,就能实现互联互通,即从每个地堡出发都能到达其他任何一个地堡(允许经过别的地堡)。
连长精心谋算,在m个设计规划中选取了挖掘总距离最短且能保证互联互通的若干个暗道规划实施了挖掘,完成了第一期的施工任务后又接受了第二期的施工任务,要求选择一个地堡进行扩建改造,使其能向每个地堡提供弹药。为了让弹药供应更及时、更快捷,从改扩建的地堡到最远地堡的距离(称为最远输送距离)应当尽量小。
你的任务是先求出第一期施工挖掘的总距离,再求改扩建地堡最远输送距离的最小值。
输入描述 Input Description
其中第一行是n和m,m>=n
下面的m行每行3个数xi、yi、zi,表示xi到yi的距离是zi
zi<1000000且m个距离互不相等
输出描述 Output Description
共包含两行,每行一个整数,
第一行是第一期的挖掘总距离,第二行是最远输送距离的最小值。
样例输入 Sample Input
4 5
1 2 1
2 3 2
3 4 3
4 1 4
3 1 5
样例输出 Sample Output
6
3
数据范围及提示 Data Size & Hint
【样例说明】
第一期挖掘1到2、2到3和3到4的3条暗道,第二期选择3号地堡进行改扩建,最远输送距离是3
【数据规模】
60%的数据 n<10且m<20
80%的数据 n<1000且m<2000
100%的数据 n<100000且m<200000
分类标签 Tags 点此展开
思路:先跑最小生成树,得出第一个答案。
第二期任务是要求最远距离最小,我们可以很容易的得出以下结论:这个点一定位于这棵树的直径上,并且是这棵树的直径的中点。
找到这个点后,再跑一个spfa或者dfs,找出离这个点最远的点,这个距离就是答案。
错因:别忘了开long long。
#include<queue> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define MAXNCNT 100010 #define MAXEDGE 200010 using namespace std; long long ans,ans2; int n,m,tot,src,decc,home; long long minn=0x7f7f7f7f,mann=0x7f7f7f7f; long long dis[MAXNCNT],cap[MAXEDGE*2]; long long sum1[MAXNCNT],sum2[MAXNCNT]; int fa[MAXNCNT],dad[MAXNCNT],vis[MAXNCNT]; int to[MAXEDGE*2],net[MAXEDGE*2],head[MAXNCNT]; struct nond{ int u,v;long long w; }v[MAXEDGE]; int abs(int x){ return x>0?x:-x; } int cmp(nond a,nond b){ return a.w<b.w; } int find(int x){ return fa[x]==x?x:fa[x]=find(fa[x]); } void add(int u,int v,long long w){ to[++tot]=v;cap[tot]=w;net[tot]=head[u];head[u]=tot; to[++tot]=u;cap[tot]=w;net[tot]=head[v];head[v]=tot; } void spfa(int s){ queue<int>que; memset(vis,0,sizeof(vis)); memset(dis,0x7f,sizeof(dis)); dis[s]=0;vis[s]=1;que.push(s); while(!que.empty()){ int now=que.front(); que.pop();vis[now]=0; for(int i=head[now];i;i=net[i]) if(dis[to[i]]>dis[now]+cap[i]){ dis[to[i]]=dis[now]+cap[i]; if(!vis[to[i]]){ vis[to[i]]=1; que.push(to[i]); } } } } void dfs(int now){ for(int i=head[now];i;i=net[i]) if(dis[to[i]]==-1){ dis[to[i]]=dis[now]+cap[i]; dfs(to[i]); } } void dfs1(int now){ for(int i=head[now];i;i=net[i]) if(dad[now]!=to[i]){ dad[to[i]]=now; sum1[to[i]]=sum1[now]+cap[i]; dfs1(to[i]); } } void dfs2(int now){ for(int i=head[now];i;i=net[i]) if(dad[now]!=to[i]){ dad[to[i]]=now; sum2[to[i]]=sum2[now]+cap[i]; dfs2(to[i]); } } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%d%d%lld",&v[i].u,&v[i].v,&v[i].w); sort(v+1,v+1+m,cmp); for(int i=1;i<=n;i++) fa[i]=i; for(int i=1;i<=m;i++){ int dx=find(v[i].u); int dy=find(v[i].v); if(dx==dy) continue; fa[dy]=dx;ans+=v[i].w; add(v[i].u,v[i].v,v[i].w); } printf("%lld\n",ans); memset(dis,-1,sizeof(dis)); decc=1;dis[decc]=0;dfs(decc); for(int i=1;i<=n;i++) if(dis[i]>dis[decc]) decc=i; memset(dis,-1,sizeof(dis)); dis[decc]=0;dfs(decc);src=decc; for(int i=1;i<=n;i++) if(dis[i]>dis[decc]) decc=i; dfs1(src);memset(dad,0,sizeof(dad)); dfs2(decc);memset(dad,0,sizeof(dad)); for(int i=1;i<=n;i++){ long long little=abs(sum1[i]-sum2[i]); if(little<minn){ mann=sum1[i];home=i;minn=little; } else if(little==minn) if(sum1[i]<mann){ mann=sum1[i];home=i; } } spfa(home); for(int i=1;i<=n;i++) if(i!=home&&dis[i]>ans2) ans2=dis[i]; cout<<ans2; }
原文地址:https://www.cnblogs.com/cangT-Tlan/p/8831065.html