架设电话线
jzoj 2132
题目大意:
给你一个图,让你从1走到n,问如果可以使k条路的代价变为0(自选),那途中走的路的最大值最小是多少
样例输入
5 7 1
1 2 5
3 1 4
2 4 8
3 2 3
5 2 9
3 4 7
4 5 6
输入说明:
一共有5根废弃的电话线杆。电话线杆1不能直接与电话线杆4、5相连。电话线杆5不能直接与电话线杆1、3相连。其余所有电话线杆间均可拉电话线。电信公司可以免费为FJ连结一对电话线杆。
样例输出
4
输出说明:
FJ选择如下的连结方案:1->3;3->2;2->5,这3对电话线杆间需要的电话线的长度分别为4、3、9。FJ让电信公司提供那条长度为9的电话线,于是,他所需要购买的电话线的最大长度为4。
数据范围
1⩽K⩽N⩽1,0001 \leqslant K\leqslant N \leqslant 1,0001⩽K⩽N⩽1,000
1⩽P⩽10,0001 \leqslant P\leqslant 10,0001⩽P⩽10,000
1⩽Li⩽1,000,0001 \leqslant L_i \leqslant 1,000,0001⩽Li⩽1,000,000
n为点的总数,p为路的总数,l为路的权值,K如题目大意所叙
解题思路:
我们可以先二分答案,然后把权值大于midmidmid的路设为1,然后跑spfa,如果结果小于k就说明可行
代码:
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m,k,x,y,z,l,r,pd,mid,tot,top,head[1500],b[1500],p[1500],s[10500],pp[1000500];
struct rec
{int to,l,next;
}a[20500];
int js(int aa,int bb){return aa>bb?1:0;}//大于条件的就是1
int spfa(int maxx)
{memset(b,127/3,sizeof(b));//预处理memset(p,0,sizeof(p));queue<int>d;d.push(1);p[1]=1;b[1]=0;while(!d.empty())//spfa{int h=d.front();d.pop();for (int i=head[h];i;i=a[i].next)if (b[h]+js(a[i].l,maxx)<b[a[i].to]){b[a[i].to]=b[h]+js(a[i].l,maxx);if (!p[a[i].to]){p[a[i].to]=1;d.push(a[i].to);}}p[h]=0;}if (b[n]==b[0]) return 0;//无解else if (b[n]<=k) return 1;//可行else return 2;//不可行
}
int main()
{scanf("%d %d %d",&n,&m,&k);for (int i=1;i<=m;++i){scanf("%d %d %d",&x,&y,&z);a[++tot].to=y;//存边a[tot].l=z;a[tot].next=head[x];head[x]=tot;a[++tot].to=x;a[tot].l=z;a[tot].next=head[y];head[y]=tot;if (!pp[z]) s[++top]=z;//把所有的权值存进来,用于二分}s[++top]=0;//为了处理k>最小边数sort(s+1,s+1+top);//排序l=1;r=top;while(l<r){mid=(l+r)>>1;//求中间值pd=spfa(s[mid]);if (!pd) {printf("-1");return 0;}else if (pd&1) r=mid;else l=mid+1;}printf("%d",s[l]);
}