HDU-4807-Lunch Time(二分+费用流,思维)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4807
题目大意:n个点,m条边,k个人从点0到点n-1。有向图(题目中没有说)每条边长度1,有最大的人流承受量。人的速度是1.求所有人都到n-1点的时间。
思路:一开始的时候以为是最大流,写了个板子后才发现还有速度的限制。。
把长度堪称费用。跑一次费用流,对于每此的残留网络都记录下来。(意思是不同时间能够到达的人数)。然后二分时间。
控制最长的时间消耗。二分出第一个符合要求的时间,这个时间就是ans。
二分的条件就是所有时间消耗在mid之前的所有流量控制,都获得综合的人数,判断是否可以到n-1人数多于k。
ACCode:
// luogu-judger-enable-o2
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<time.h>
#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
#define Pair pair<int,int>
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// 水印
//std::ios::sync_with_stdio(false);
// register
const int MAXN=3e3+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll mod=192600817;
const double EPS=1.0e-8;
const double PI=acos(-1.0);
struct Node1{
int v,w,cost,nxt;
Node1(int _v=0,int _w=0,int _cost=0,int _nxt=0){
v=_v;w=_w;cost=_cost;nxt=_nxt;
}
};
struct Node2{
ll cost,flow;
Node2(ll _cost=0,ll _flow=0){
cost=_cost;flow=_flow;
}
};
Node2 Ans[MAXN];
Node1 Edge[MAXN<<2];
int Head[MAXN],Ecnt;
int Pre[MAXN],Dis[MAXN],Flow[MAXN],Last[MAXN];
int Vis[MAXN];
int maxw,Cnt;
int n,m,k,S,T;
void Intt(){
clean(Head,-1);Ecnt=0;
maxw=0;Cnt=0;
}
void Add(int u,int v,int w,int cost){
Edge[Ecnt]=Node1(v,w,cost,Head[u]);
Head[u]=Ecnt++;
Edge[Ecnt]=Node1(u,0,-cost,Head[v]);
Head[v]=Ecnt++;
}
int SPFA(){
clean(Vis,0);Vis[S]=1;
clean(Dis,INF32);Dis[S]=0;
Flow[S]=INF32;Pre[T]=-1;
queue<int> que;que.push(S);
while(que.size()){
int u=que.front();que.pop();
Vis[u]=0;
for(int i=Head[u];i+1;i=Edge[i].nxt){
int temp=Edge[i].v;
if(Edge[i].w>0&&Dis[temp]>Dis[u]+Edge[i].cost){
Dis[temp]=Dis[u]+Edge[i].cost;
Flow[temp]=min(Flow[u],Edge[i].w);
Last[temp]=i;
Pre[temp]=u;
if(Vis[temp]==0){
Vis[temp]=1;que.push(temp);
}
}
}
}return Dis[T]==INF32?0:1;
}
void MCMF(){
while(SPFA()){
// cout<<Cnt<<" "<<Dis[T]<<endl;
int u=T;Cnt++;
maxw+=Flow[T];
Ans[Cnt]=Node2(Dis[T],Flow[T]);
while(u!=S){
Edge[Last[u]].w-=Flow[T];
Edge[Last[u]^1].w+=Flow[T];
u=Pre[u];
}
}
}
ll Judge(ll mid){//最多花费mid时间来行走
ll tot=0;
for(int i=1;i<=Cnt;++i){
if(Ans[i].cost<=mid){
tot+=Ans[i].flow*(mid-Ans[i].cost+1);
}
}return tot;
}
int main(){
while(~scanf("%d%d%d",&n,&m,&k)){
int a,b,w;Intt();
for(int i=1;i<=m;++i){
scanf("%d%d%d",&a,&b,&w);
Add(a,b,w,1);
}S=0;T=n-1;
if(k==0){
printf("0\n");continue;
}MCMF();
// cout<<1<<endl;
if(maxw==0){
printf("No solution\n");continue;
}ll l=1,r=1e9,mid;
// for(int i=1;i<=Cnt;++i){
// cout<<Ans[i].cost<<" "<<Ans[i].flow<<endl;
// }
//第一个符合要求的答案。
while(l<=r){
mid=(l+r)>>1;
if(Judge(mid)>=k) r=mid-1;
else l=mid+1;
}printf("%d\n",l);
}
}
总算写完这道题了。当时比赛的时候,上来就开了这一道。。结果最后所有队伍就一个队写出来了。我在上面肝了2个小时,放弃。脸真黑。不过这个题写起来还不错,是个好题。