COGS 2095. 不平凡的引线
2095. 不平凡的引线
★☆ 输入文件:firelead.in
输出文件:firelead.out
简单对比
时间限制:1 s
内存限制:256 MB
【题目描述】
这里说的引线是炮仗的引线,它可以匀速的燃烧。熊孩子经常会把引线抽出,点引线玩。但是有些熊孩子看到这些并不满足,于是他们把引线的形状摆成一棵树。同时点燃所有的叶子结点,多少单位时间后引线才能燃烧完?可以认为每个单位时间会燃烧一个单位长度的引线。
如上图共有3条引线,其中(1,2)引线的单位长度为2,(2,3)引线单位长度为1,(2,4)引线单位长度为1。现在同时点燃所有叶子结点(叶子结点 定义为只与一条边相邻的结点,如上图中的叶子结点为1,3,4)。1个单位时间以后,(2,3),(2,4)被完全烧完,(1,2)仅剩一半。这时剩下的 半段(1,2)两头均被引燃,所以再过0.5个单位时间后,(1,2)被完全烧完。共需1.5个单位时间。
【输入格式】
第一行一个整数m,表示共有m条引线。
接下来m行,每行三个整数u,v,len表示有一条引线两端分别是u和v,其长度为len
【输出格式】
一个浮点数,表示需要多少单位时间引线会燃烧完,保留一位小数。
【样例输入】
3 1 2 2 2 3 1 2 4 1
【样例输出】
1.5
【提示】
数据范围与约定:
对于30%的数据:m+1 <= 100,保证引线长度均为1
对于60%的数据:m+1 <= 1000,保证引线长度均为1
对于100%的数据:m+1 <= 100000,保证输入的引线一定可以构成一棵树,引线的长度len满足1 <= len <= 10000。
m条边的节点标号范围从1到m+1
题解:
这个题目真的妙不可言,考试的时候只想到模拟。
好了,这个题目求每条边被烧到的时间非常困难,直接求是n平方的,所以我们考虑先求出每个点被烧到的时间,显然是当前节点到所有节点的最短路,这个取min,这个东西可以一次spfa求出来,只要把所有的点事先加如队列之中求出来的就是i这个节点到每个叶子节点的最短路(取min,并且对于图也一样)。
然后求出来点的,就可以推公式求边的了,显然答案就是所有条边被烧完的时间取max,然后考虑怎么推,当dis[to]=dis[now]+quan时(now和to是边上的两个节点,权值是边权),时间=dis[now]+quan=(dis[now]+dis[to]+quan)/2;当dis[to]<dis[now]+quan时(令dis[to]>dis[now]),时间=dis[now]+dis[to]-dis[now]+(quan-(dis[to]-dis[now]))/2=(dis[now]+dis[to]+quan)/2。(因为我们是用多源最短路求的dis,所以不存在dis[now]>dis[to]+quan)把公式带进去就可以了。
代码:
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <cmath> #include <iostream> #include <queue> #define MAXN 200100 using namespace std; struct edge{ int first; int next; int to; int quan; }a[MAXN*2]; int in[MAXN]; double dis[MAXN]; bool have[MAXN]; int m,num=0,n; queue<int> q; void addedge(int from,int to,int quan){ a[++num].to=to; a[num].quan=quan; a[num].next=a[from].first; a[from].first=num; } void spfa(){ while(!q.empty()) q.pop(); memset(dis,127,sizeof(dis)); for(int i=1;i<=n;i++){ if(in[i]==1){ dis[i]=0,q.push(i),have[i]=1; } } while(!q.empty()){ int now=q.front(); q.pop();have[now]=0; for(int i=a[now].first;i;i=a[i].next){ int to=a[i].to,quan=a[i].quan; if(dis[to]>dis[now]+quan){ dis[to]=dis[now]+quan; if(!have[to]){ have[to]=1; q.push(to); } } } } } int main() { scanf("%d",&m);n=m+1; for(int i=1;i<=m;i++){ int x,y,z;scanf("%d%d%d",&x,&y,&z); addedge(x,y,z); addedge(y,x,z); in[x]++;in[y]++; } spfa(); double ans=0; for(int now=1;now<=n;now++){ for(int i=a[now].first;i;i=a[i].next){ int to=a[i].to,quan=a[i].quan; double x=(dis[now]+dis[to]+quan)/2.0; ans=max(ans,x); } } printf("%0.1f",ans); return 0; }