【POJ3662】Telephone Lines dij + 二分答案
阿新 • • 發佈:2018-11-03
題目大意:給定一個 N 個頂點,M 條邊的無向圖,求一條從 1 號節點到 N 號節點之間的路徑,使得第 K+1 大的邊權最小,若 1 與 N 不連通,輸出 -1。
最小化最大值一類的問題,採用二分答案即可,每次跑一遍 dij ,若邊權大於二分的值,那麼等效邊權為1,否則邊權為0,最後判斷從 1 到 N 之間的最短路是否大於 K 即可。
程式碼如下
#include <cstdio> #include <algorithm> #include <memory.h> #include <queue> using namespace std; const int maxv=1e3+10; const int maxe=1e4+10; struct node{ int nxt,to,w; node(int x=0,int y=0,int z=0):nxt(x),to(y),w(z){} }e[maxe<<1]; int tot=1,head[maxv]; int n,m,k,dis[maxv],mx; bool vis[maxv]; void add_edge(int from,int to,int w){ e[++tot]=node(head[from],to,w),head[from]=tot; } void read_and_parse(){ scanf("%d%d%d",&n,&m,&k); for(int i=1,from,to,w;i<=m;i++){ scanf("%d%d%d",&from,&to,&w); add_edge(from,to,w),add_edge(to,from,w); mx=max(mx,w); } } typedef pair<int,int> P; bool right(int x){ memset(dis,0x3f,sizeof(dis)); memset(vis,0,sizeof(vis)); priority_queue<P> q; dis[1]=0,q.push(make_pair(0,1)); while(q.size()){ int u=q.top().second;q.pop(); if(vis[u])continue; if(u==n)break; vis[u]=1; for(int i=head[u];i;i=e[i].nxt){ int v=e[i].to,w=(e[i].w>x?1:0); if(dis[v]>dis[u]+w){ dis[v]=dis[u]+w; q.push(make_pair(-dis[v],v)); } } } return dis[n]<=k; } bool dij(){ memset(dis,0x3f,sizeof(dis)); memset(vis,0,sizeof(vis)); priority_queue<P> q; dis[1]=0,q.push(make_pair(0,1)); while(q.size()){ int u=q.top().second;q.pop(); if(vis[u])continue; if(u==n)break; vis[u]=1; for(int i=head[u];i;i=e[i].nxt){ int v=e[i].to,w=e[i].w; if(dis[v]>dis[u]+w){ dis[v]=dis[u]+w; q.push(make_pair(-dis[v],v)); } } } return dis[n]==0x3f3f3f3f; } void solve(){ int l=0,r=mx; while(l<r){ int mid=l+r>>1; if(right(mid))r=mid; else l=mid+1; } printf("%d\n",l); } int main(){ read_and_parse(); if(dij())return puts("-1"),0; solve(); return 0; }