攻佔城堡
時間限制: 1 Sec 內存限制: 128 MB
題目描述
whitecloth要去攻佔rainbow和freda的城堡,從whitecloth的出發點到城堡之間有
N個據點,whitecloth在1號點,城堡在N號點,中間有M條雙向道路,每條道
路上都有兵力把守,whitecloth想要攻佔城堡,就要佔領據點之間的道路從而得到
一條通往城堡的路,whitecloth要使用的兵力等與他所攻佔的道路中把守兵力的最
大值。
現在by也來幫助whitecloth攻佔城堡,by可以幫助whitecloth攻佔最多K條道路
(由whitecloth來選擇),在這樣的情況下,whitecloth想知道他最少用多少兵力
就可以攻佔城堡?
輸入
第一行,三個數N, M, K,表示據點數,道路數,和by可以幫whitecloth攻佔
的道路數量。
接下來M行,每行三個數u,v,p,表示一條道路的兩個端點和把守的兵力。
輸出
一個數,表示whitecloth用的最少的兵力。
//太坑了。題目沒說,如果1到N不連通要輸出-1 。。。
樣例輸入
5 7 1
1 2 5
3 1 4
2 4 8
3 2 3
5 2 9
3 4 7
4 5 6
樣例輸出
4
提示
【數據範圍】
N ≤ 1000,M ≤ 10000,1 ≤ u, v ≤ N, 0 ≤ p ≤ 1000000
解題報告
對於這種只輸出一個可以爲約束條件答案的題目一般一眼就二分答案
發現答案具有單調性(越大越可能判定成功)
於是決定二分路徑上的最大邊。
然後用spfa判定能否到達
判定時如果當前邊的權值小於等於mid那麼把這條邊的長度當做0
否然把這條邊的權值當做1(代表需要by來攻下這條邊)
最短路跑完後看一眼dis[n]是否小於k就可以了。
O(mlogp)11ms通過
#include<cstdio>
#include<queue>
#include<cstring>
const int MAXN=1200;
const int MAXM=12000;
const int INF=0x3f3f3f3f;
int getint(){
int ret=0;char ch;
while((ch=getchar())<'0'||ch>'9');
do{ret*=10;ret+=ch-'0';}while((ch=getchar())>='0'&&ch<='9');
return ret;
}
inline int max(int a,int b)
{return a>b?a:b;}
struct Node{
int v,w,nxt;
}d[MAXM*3];
int head[MAXN],etot;
inline void addedge(int a,int b,int c){
etot++;
d[etot].v=b;
d[etot].w=c;
d[etot].nxt=head[a];
head[a]=etot;
}
int dis[MAXN];
bool vis[MAXN];
std::queue<int >que;
int n,m,k,mid;
void check(int s){
memset(dis,0x3f,sizeof dis);
dis[s]=0;
vis[s]=true;
que.push(s);
while(!que.empty()){
int u=que.front();
que.pop();
vis[u]=false;
for(int e=head[u];e;e=d[e].nxt)
if(dis[d[e].v]>dis[u]+(d[e].w>mid)){
dis[d[e].v]=dis[u]+(d[e].w>mid);
if(!vis[d[e].v]){
que.push(d[e].v);
vis[d[e].v]=true;
}
}
}
}
int main(){
n=getint();m=getint();k=getint();
int l,r;
l=r=0;
for(int i=1;i<=m;i++){
int a=getint(),b=getint(),c=getint();
addedge(a,b,c);
addedge(b,a,c);
r=max(r,c);
}
if(!m){puts("-1");return 0;}
while(l<r){
mid=(l+r)>>1;
check(1);
if(dis[n]==INF){puts("-1");return 0;}
if(dis[n]<=k)r=mid;
else l=mid+1;
}
//mid=l;
//if(!check(1))l=r;
printf("%d\n",l);
}