[Usaco2007 Jan]Telephone Lines架设电话线
生活随笔
收集整理的這篇文章主要介紹了
[Usaco2007 Jan]Telephone Lines架设电话线
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目描述
FarmerJohn打算將電話線引到自己的農場,但電信公司并不打算為他提供免費服務。于是,FJ必須為此向電信公司支付一定的費用。FJ的農場周圍分布著N(1<=N<=1,000)根按1..N順次編號的廢棄的電話線桿,任意兩根電話線桿間都沒有電話線相連。一共P(1<=P<=10,000)對電話線桿間可以拉電話線,其余的那些由于隔得太遠而無法被連接。第i對電話線桿的兩個端點分別為A_i、B_i,它們間的距離為L_i(1<=L_i<=1,000,000)。數據中保證每對{A_i,B_i}最多只出現1次。編號為1的電話線桿已經接入了全國的電話網絡,整個農場的電話線全都連到了編號為N的電話線桿上。也就是說,FJ的任務僅僅是找一條將1號和N號電話線桿連起來的路徑,其余的電話線桿并不一定要連入電話網絡。經過談判,電信公司最終同意免費為FJ連結K(0<=K<N)對由FJ指定的電話線桿。對于此外的那些電話線,FJ需要為它們付的費用,等于其中最長的電話線的長度(每根電話線僅連結一對電話線桿)。如果需要連結的電話線桿不超過K對,那么FJ的總支出為0。請你計算一下,FJ最少需要在電話線上花多少錢。
輸入格式
第1行: 3個用空格隔開的整數:N,P,以及K
第2..P+1行: 第i+1行為3個用空格隔開的整數:A_i,B_i,L_i
輸出格式
第1行: 輸出1個整數,為FJ在這項工程上的最小支出。
如果任務不可能完成, 輸出-1
容易想到的策略是:把1~n路徑上花費最高的k條路徑去掉。所以我們可以枚舉每條路徑并枚舉路徑上的每條邊來解答。但這顯然不是我們能夠接受的復雜度。
我們需要換一種思路來做。我們來分析一下答案的性質:
設答案為ans,那么在1~n的所有路徑中lenth<=ans的都可以免費,其余的計入k條免費線路中。如果ans過小,那么lenth>ans的路徑數可能大于k,如果過大則得不到最優解。所以我們可以二分答案,對于每個二分出的limitation,把邊長大于它的路線的代價改成1,其余的代價為0。然后跑一遍最短路,看最短路長度是否≤k即可。
最短路可以用Dijkstra+Heap做到O((N+M) * logN),二分答案的復雜度為O(logAns),所以總復雜度為:
\[ O((N+M)logNlogAns) \]
可以通過本題。
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<queue> #define maxn 1001 #define maxm 10001 using namespace std;struct edge{int to,next,dis;edge(){}edge(const int &_to,const int &_dis,const int _next){to=_to,dis=_dis,next=_next;} }e[maxm<<1]; int head[maxn],k;int dis[maxn],maxlen,ans; bool vis[maxn]; int n,m,t; priority_queue< pair<int,int>,vector< pair<int,int> >,greater< pair<int,int> > > q;inline int read(){register int x(0),f(1); register char c(getchar());while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();return x*f; } inline void add(const int &u,const int &v,const int &w){e[k]=edge(v,w,head[u]);head[u]=k++; }inline void dijkstra(const int &lim){memset(dis,0x3f,sizeof dis);memset(vis,false,sizeof vis);q.push(make_pair(0,1));dis[1]=0;while(q.size()){int u=q.top().second; q.pop();if(vis[u]) continue; vis[u]=true;for(register int i=head[u];~i;i=e[i].next){int v=e[i].to;if(dis[v]>dis[u]+(e[i].dis>lim))dis[v]=dis[u]+(e[i].dis>lim),q.push(make_pair(dis[v],v));}} }int main(){memset(head,-1,sizeof head);n=read(),m=read(),t=read();for(register int i=1;i<=m;i++){int u=read(),v=read(),w=read();add(u,v,w),add(v,u,w);if(maxlen<w) maxlen=w;}int l=0,r=maxlen,flag=false;while(l<=r){int lim=l+r>>1;dijkstra(lim);if(dis[n]<=t) flag=true,ans=lim,r=lim-1;else l=lim+1;}printf("%d\n",flag?ans:-1);return 0; }轉載于:https://www.cnblogs.com/akura/p/10848893.html
總結
以上是生活随笔為你收集整理的[Usaco2007 Jan]Telephone Lines架设电话线的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [Usaco2008 Feb]Eatin
- 下一篇: vcsa清单配置和事件备份