题目:http://poj.org/problem?id=3662
二分答案找出符合条件的最小长度;
假设了每个长度后,以这个为标准对每条边赋值,0为小于等于,1为大于,然后按这个值来跑最短路,在看看能否使用不超过k根长电线;
注意不能到达要输出-1!
不知为何l从0开始就A了,从最短的电线开始就是WA,可怖的细节;
总之,0和1这个技巧很美,打破了最短路的常规思路。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; queue<int>q; int n,p,k,head[1005],ct,l,r,dis[1005]; bool vis[1005]; struct N{ int to,next,w,c; N(int t=0,int n=0,int w=0):to(t),next(n),w(w) {} }edge[20005]; bool spfa() { memset(vis,0,sizeof vis); memset(dis,3,sizeof dis); while(q.size())q.pop(); q.push(1);vis[1]=1;dis[1]=0; while(q.size()) { int x=q.front();q.pop(); vis[x]=0; for(int i=head[x];i;i=edge[i].next) { int u=edge[i].to; if(dis[u]>dis[x]+edge[i].c) { dis[u]=dis[x]+edge[i].c; if(!vis[u]) { vis[u]=1; q.push(u); } } } } return dis[n]<=k; } bool cl(int x) { for(int i=1;i<=ct;i++) { if(edge[i].w<=x)edge[i].c=0; else edge[i].c=1; } return spfa(); } int main() { while(scanf("%d%d%d",&n,&p,&k)==3) { ct=0; memset(head,0,sizeof head); // l=1000005;//!! l=0; r=0; int x,y,z; for(int i=1;i<=p;i++) { scanf("%d%d%d",&x,&y,&z); edge[++ct]=N(y,head[x],z);head[x]=ct; edge[++ct]=N(x,head[y],z);head[y]=ct; r=max(r,z); // l=min(l,z); } // while(l<r) // { // int mid=(l+r)/2; // if(cl(mid))r=mid; // else l=mid+1; // } int ans=-1;//!!! while(l<=r) { int mid=(l+r)/2; if(cl(mid)) { ans=mid; r=mid-1; } else l=mid+1; } printf("%d\n",ans); } return 0; }