LuoguP1948 电话线 【二分答案/图论】
其实是和奥格瑞玛一样的题啦。
但还是想了很久后看了题解。
多年以后,笨笨长大了,成为了电话线布置师。由于地震使得某市的电话线全部损坏,笨笨是负责接到震中市的负责人。该市周围分布着N(1<=N<=1000)根据1……n顺序编号的废弃的电话线杆,任意两根线杆之间没有电话线连接,一共有p(1<=p<=10000)对电话杆可以拉电话线。其他的由于地震使得无法连接。
第i对电线杆的两个端点分别是ai,bi,它们的距离为li(1<=li<=1000000)。数据中每对(ai,bi)只出现一次。编号为1的电话杆已经接入了全国的电话网络,整个市的电话线全都连到了编号N的电话线杆上。也就是说,笨笨的任务仅仅是找一条将1号和N号电线杆连起来的路径,其余的电话杆并不一定要连入电话网络。
电信公司决定支援灾区免费为此市连接k对由笨笨指定的电话线杆,对于此外的那些电话线,需要为它们付费,总费用决定于其中最长的电话线的长度(每根电话线仅连接一对电话线杆)。如果需要连接的电话线杆不超过k对,那么支出为0.
请你计算一下,将电话线引导震中市最少需要在电话线上花多少钱?如果无解,输出-1。
输入输出格式
输入格式:
输入文件的第一行包含三个数字n,p,k;
第二行到第p+1行,每行分别都为三个整数ai,bi,li。
输出格式:
一个整数,表示该项工程的最小支出,如果不可能完成则输出-1.
题设:最长的电话线花费最少是多少 。
同样是一道二分答案。
我们仿照上一题,二分最后的花费(最长电话线的长度)。
但是这题比较 特别的是电信(移动)公司会免费提供k条线路。这个条件怎么用?因为是免费的,所以我们肯定贪心地想要先把这几条线路用在比当前二分出的答案长的道路上,把钱花在刀刃上嘛。这个思想怎么实现?我们可以在每次的spfacheck中把比当前答案大的边设为1,比当前长度小的答案设为0.,于是我们就成功地重载了dis数组的含义,他不再表示最短路程长度,而是用了优惠的边的个数。
其他注意事项:左边界为0(因为题目中说有不超过k对的情况),连两次边。
难点:转化dis数组的含义,利用免费搭建k对的条件。
code
1 #include<cstdio> 2 #include<algorithm> 3 #include<queue> 4 #include<cstring> 5 6 using namespace std; 7 const int inf=0x7f7f7f7f; 8 9 int n,p,k,tot,mx,s; 10 int head[20000],visit[20000],dis[20000]; 11 struct node{ 12 int to,next,val; 13 }edge[20000]; 14 15 void add(int x,int y,int z) 16 { 17 edge[++tot].to=y; 18 edge[tot].val=z; 19 edge[tot].next=head[x]; 20 head[x]=tot; 21 } 22 23 bool spfa_check(int cnt) 24 { 25 memset(visit,0,sizeof(visit)); 26 for(int i=1;i<=n;i++) dis[i]=inf; 27 queue<int>q; 28 dis[1]=0;visit[1]=1;q.push(1); 29 while(!q.empty()) 30 { 31 int x=q.front(); 32 q.pop();visit[x]=0; 33 for(int i=head[x];i;i=edge[i].next) 34 { 35 int y=edge[i].to; 36 if(edge[i].val>cnt) s=dis[x]+1; 37 else s=dis[x]; 38 if(s<dis[y]) 39 { 40 dis[y]=s; 41 if(!visit[y]) 42 { 43 visit[y]=1; 44 q.push(y); 45 } 46 } 47 } 48 } 49 if(dis[n]<=k) return 1; 50 return 0; 51 } 52 53 int main() 54 { 55 scanf("%d%d%d",&n,&p,&k); 56 for(int i=1;i<=p;i++) 57 { 58 int u=0,v=0,w=0; 59 scanf("%d%d%d",&u,&v,&w); 60 mx=max(mx,w); 61 add(u,v,w); 62 add(v,u,w); 63 } 64 int l=0,r=mx; 65 if(!spfa_check(r)) 66 { 67 printf("-1"); 68 return 0; 69 } 70 while(l<r) 71 { 72 int mid=(l+r)>>1; 73 if(spfa_check(mid)) r=mid; 74 else l=mid+1; 75 } 76 printf("%d",l); 77 return 0; 78 }