攻占城堡
时间限制: 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);
}