hiho#1139 : 二分·二分答案

http://hihocoder.com/problemset/problem/1139
时间限制: 10000ms
单点时限: 1000ms
内存限制: 256MB

描述

在上一回和上上回里我们知道Nettle在玩《艦これ》,Nettle在整理好舰队之后终于准备出海捞船和敌军交战了。
在这个游戏里面,海域是N个战略点(编号1..N)组成,如下图所示
hiho#1139 : 二分·二分答案_第1张图片
其中红色的点表示有敌人驻扎,猫头像的的点表示该地图敌军主力舰队(boss)的驻扎点,虚线表示各个战略点之间的航线(无向边)
在游戏中要从一个战略点到相邻战略点需要满足一定的条件,即需要舰队的索敌值大于等于这两点之间航线的索敌值需求。
由于提高索敌值需要将攻击机、轰炸机换成侦察机,舰队索敌值越高,也就意味着舰队的战力越低。
另外在每一个战略点会发生一次战斗,需要消耗1/K的燃料和子弹。必须在燃料和子弹未用完的情况下进入boss点才能与boss进行战斗,所以舰队最多只能走过K条航路。
现在Nettle想要以最高的战力来进攻boss点,所以他希望能够找出一条从起始点(编号为1的点)到boss点的航路,使得舰队需要达到的索敌值最低,并且有剩余的燃料和子弹。

特别说明:两个战略点之间可能不止一条航线,两个相邻战略点之间可能不止一条航线。保证至少存在一条路径能在燃料子弹用完前到达boss点。

提示:你在找什么?

输入

第1行:4个整数N,M,K,T。N表示战略点数量,M表示航线数量,K表示最多能经过的航路,T表示boss点编号, 1≤N,K≤10,000, N≤M≤100,000
第2..M+1行:3个整数u,v,w,表示战略点u,v之间存在航路,w表示该航路需求的索敌值,1≤w≤1,000,000。

输出

第1行:一个整数,表示舰队需要的最小索敌值。

样例输入
5 6 2 5
1 2 3
1 3 2
1 4 4
2 5 2
3 5 5
4 5 3
样例输出
3
题目大意:求出从1到t经过不多于K条边的路径的最小的索敌值。索敌值可以理解为这条路径上的最大权值(w)
对于这种求最值而且正向思维有有点麻烦(考录到会超时)可以选择枚举答案(二分答案)
为什么可以二等答案?。。。。因为最值必然存在临界情况
官方题解;

我们需要找什么?
在这个题目中我们需要找的是路径最长边。比如存在一条路径{1, p[1], p[2], ... , p[j], T}, p = {p[1],p[2],...,p[j]]}, j < K,我们需要找的为 D(P) = Max{w(1, p[1]), w(p[j], T), Max{w(p[i], p[i+1]) | 1 <= i < j} }。则这道题的结果为找出所有从1到T的路径P',求的Min{D(P')}。由于给定的图存在环,所以要枚举出所有1到T的路径是很难的,因此我们需要换个角度去思考这个问题。

这道题结果有什么特殊性?
不妨假设答案为j,如果舰队满足j以上的索敌值,那么一定存在至少一条路径可以从1到T,并且路径数量小于K。
并且如果舰队索敌值小于j,则在K条路径的条件下一定无法从1到T。否则j就不是最小值了。
则对于索敌值满足这样一个关系:
hiho#1139 : 二分·二分答案_第2张图片
可以看出,j值刚好是是否存在路径的一个分界线。如果我们枚举一个j':

  • j'<j,无法到达boss点

  • j'>=j,一定可以到达boss点

则如何快速的找到这个分界线j,就是解决这道题目的关键。

不妨设f(x) = true(索敌值为x时,可以达到boss点), false(索敌值为x时,不能达到boss点)
1.从小到大枚举j',当出现第一个f(k')=true时,j'=j。需要枚举j次,若j很大时,该算法很低效。
2.二分枚举,设定枚举区间[L,R],满足f(L)=false, f(R)=true。每次取中间值Mid=(L+R)/2,若f(Mid)=true,令R=Mid;否则令L=Mid。
当L+1=R时,可以知道R即为我们需要寻找的j。

最后一个问题便是f(x)怎么来写,我想这个你一定可以解决掉,另外别忘了限制了路径长度为K。
具体实现代码:

/* ***********************************************
Author :
Created Time :2015/6/25 23:42:07
File Name :1.cpp
************************************************ */
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <iomanip>
#include <list>
#include <deque>
#include <stack>
#define ull unsigned long long
#define ll long long
#define mod 90001
#define INF 1<<30
#define maxn 100000+10
#define cle(a) memset(a,0,sizeof(a))
const ull inf = 1LL << 61;
const double eps=1e-5;
using namespace std;
struct node{
int v,cap,next;
}E[2*maxn];
int pre[maxn],vis[maxn];
int p[maxn];
int m,n,l,k,t;
void add(int u,int v,int cap){
E[l].v=v;
E[l].cap=cap;
E[l].next=pre[u];
pre[u]=l++;
}
typedef pair<int,int>pii;
bool cmp(int a,int b){
return a>b;
}
bool bfs(int kk){
cle(vis);
queue<pii>q;
q.push(make_pair(1,0));
vis[1]=1;
while(!q.empty()){
pii u=q.front();q.pop();
//cout<<u.first<<endl;
if(u.first==t&&u.second<=k)return true;
for(int i=pre[u.first];i+1;i=E[i].next){
int v=E[i].v,cap=E[i].cap;
//cout<<u.first<<endl;
if(!vis[v]&&cap<=kk){
pii pt;
vis[v]=1;
pt.first=v,pt.second=u.second+1;
q.push(pt);
}
}
}
return false;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
//freopen("out.txt","w",stdout);
while(cin>>n>>m>>k>>t){
int x,y,z;
l=0;
memset(pre,-1,sizeof pre);
int Inf=-100;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
add(y,x,z);
Inf=max(Inf,z);
}
int l=0,r=Inf;
while(l<r){
int mid=(l+r)/2;
if(bfs(mid)){
r=mid;
}
else l=mid+1;
}
printf("%d\n",l);
}
return 0;
}



你可能感兴趣的:(hiho#1139 : 二分·二分答案)