POJ - 3662 Telephone Lines (Dijkstra+二分)
题意:一张带权无向图中,有K条边可以免费修建。现在要修建一条从点1到点N的路,费用是除掉免费的K条边外,权值最大的那条边的值,求最小花费。
分析:假设存在一个临界值X,小于X的边全部免费,那么此时由大于等于X的边组成的图,从点1到点N走过的边数小于等于K,那么这个X就是所求的答案。所以可以通过二分答案的方法求解该问题,每一次根据mid值跑迪杰斯特拉,d[i]记录路径长度(走过边的数目)。需要注意的是,要特判一下点1到点N本身不连通的情况以及花费为0的情况。二分的时候,当d[N]>K时修改答案为mid,因为此时能确定最后的结果一定大于等于mid。
#include<iostream> #include<stdio.h> #include<cstring> #include<queue> #include<cmath> #include<algorithm> #include<vector> using namespace std; typedef int LL; const int maxn =1e3+5; const int maxm =5e4+5; const LL INF =0x3f3f3f3f; struct Edge{ int from,to,next; LL val; bool operator <(const Edge &e) const {return val<e.val;} }; struct HeapNode{ LL d; //费用或路径 int u; bool operator < (const HeapNode & rhs) const{return d > rhs.d;} }; struct Dijstra{ int n,m,tot; Edge edges[maxm]; bool used[maxn]; LL d[maxn]; int head[maxn]; void init(int n){ this->n = n; this->tot=0; memset(head,-1,sizeof(head)); } void Addedge(int u,int v ,LL dist){ edges[tot].to = v; edges[tot].val = dist; edges[tot].next = head[u]; head[u] = tot++; } int dijkstra(int s,int limit){ memset(used,0,sizeof(used)); priority_queue<HeapNode> Q; for(int i=0;i<=n;++i) d[i]=INF; //d[i]记录的是到i点走过的权值超过limit的边数 d[s]=0; Q.push((HeapNode){0,s}); while(!Q.empty()){ HeapNode x =Q.top();Q.pop(); int u =x.u; if(d[u]<x.d) continue; //没有更新的必要,不加判断也对,但是慢一点点 for(int i=head[u];~i;i=edges[i].next){ int nd = d[u]+(edges[i].val>=limit?1:0); int v = edges[i].to; if (d[v] > nd){ d[v] = nd; Q.push({d[v], v}); } } } return d[n]; } }G; #define LOCAL int main() { #ifdef LOCAL freopen("in.txt","r",stdin); freopen("out.txt","w",stdout); #endif int N,M,K,u,v,k; LL tmp; while(scanf("%d%d%d",&N,&M,&K)==3){ G.init(N); int maxL = -1; for(int i=0;i<M;++i){ scanf("%d%d%d",&u,&v,&tmp); G.Addedge(u,v,tmp); G.Addedge(v,u,tmp); if(maxL<tmp) maxL = tmp; } int res = G.dijkstra(1,0); if(res==INF){ printf("-1\n"); continue; } else if(res<=K){ //先特判一下 printf("0\n"); continue; } int L =0,R=maxL,mid,ans; while(L<R){ mid =(L+R)>>1; if(G.dijkstra(1,mid)>K){ ans = mid; //此时能确定的是:肯定要花费mid的代价 L = mid+1; } else R =mid-1; } printf("%d\n",ans); } return 0; }
为了更好的明天