【二分答案】【最短路】bzoj1614 [Usaco2007 Jan]Telephone Lines架设电话线

对于二分出的答案x而言,验证答案等价于将所有边权>x的边赋成1,否则赋成0,然后判断从1到n的最短路是否<=K。

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define N 1001
#define M 10001
int n,m,K,Xs[M],Ys[M],Zs[M];
int first[N],next[M<<1],v[M<<1],en;
bool w[M<<1];
void AddEdge(int U,int V,bool W)
{
	v[++en]=V;
	w[en]=W;
	next[en]=first[U];
	first[U]=en;
}
queue<int>q;
bool inq[N];
int d[N];
void spfa()
{
	memset(d,0x7f,sizeof(int)*(n+1)); d[1]=0; q.push(1); inq[1]=1;
	while(!q.empty())
	  {
	  	int U=q.front();
	  	for(int i=first[U];i;i=next[i])
	  	  if(d[v[i]]>d[U]+w[i])
	  	    {
	  	      d[v[i]]=d[U]+w[i];
	  	      if(!inq[v[i]]) {q.push(v[i]); inq[v[i]]=1;}
	  	    }
	  	q.pop(); inq[U]=0;
	  }
}
bool check(int x)
{
	en=0; memset(first,0,sizeof(int)*(n+1));
	for(int i=1;i<=m;++i) {AddEdge(Xs[i],Ys[i],Zs[i]>x); AddEdge(Ys[i],Xs[i],Zs[i]>x);}
	spfa();
	return d[n]<=K;
}
int main()
{
	scanf("%d%d%d",&n,&m,&K);
	for(int i=1;i<=m;++i) scanf("%d%d%d",&Xs[i],&Ys[i],&Zs[i]);
	int l=0,r=1000001;
	while(r>l)
	  {
	  	int mid=(l+r>>1);
	  	if(check(mid)) r=mid;
	  	else l=mid+1;
	  }
	printf("%d
",l<=1000000?l:(-1));
	return 0;
}
原文地址:https://www.cnblogs.com/autsky-jadek/p/4440902.html