HDU4807 Lunch Time(费用流变种)

时间:2023-09-02 08:31:38

题目

Source

http://acm.hdu.edu.cn/showproblem.php?pid=4807

Description

The campus of Nanjing University of Science and Technology can be viewed as a graph with N vertexes and M directed edges (vertexes are numbered from 0 to N - 1). Each edge has the same length 1. Every day, there are K students walking to the dinning-hall (vertex N - 1) from the teaching building (vertex 0) at lunch time. They all want reach the dinning-hall as soon as possible. However, each edge can only serve at most ci students at any time. Can you make arrangements for students, so that the last student can reach the dinning-hall as soon as possible? (It is assumed that the speed of the students is 1 edge per unit time)

Input

There are several test cases, please process till EOF.
The first line of each test case contains three integer N(2 <= N <= 2500), M(0 <= M <= 5000), K(0 <= K <= 109). Then follows M lines, each line has three numbers ai, bi, ci(0 <= ci <= 20), means there is an edge from vertex ai to bi with the capacity ci.

Output

For each test case, print an integer represents the minimum time. If the requirements can not be met, print “No solution”(without quotes) instead.

Sample Input

5 6 4
0 1 2
0 3 1
1 2 1
2 3 1
1 4 1
3 4 2
3 3 10
0 1 1
1 2 1
0 2 1
2 0 1

Sample Output

3
6
No solution

分析

题目大概说一张有向图,同一时间边只能容量一定数量的人,k个人从0点出发,移动到下一点花费1时间,问所有人都到达n-1点最少花的时间是多少?

这题感觉很不错。

  • 跑费用流,找可以找到若干条连续最短增广路,这些最短路叠加在一起是满足容量限制条件的,或者简单说这些路径是不重合的。
  • 而对于这题,这若干条路,就相当于若干条并行的可以同时从起点出发到达终点的路径,每条路都有各自走完的时间(费用)和每次走完到达的人(流量)。
  • 或者更清晰点,这若干条路就是若干条流水线!流水线满流后,每隔一单位时间完工的物品就是流水线最大流量。所以跑费用流找到若干条路,然后模拟一下流水线即可。。

代码

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define INF (1<<30)
#define MAXN 2555
#define MAXM 11111
struct Edge{
int u,v,cap,cost,next;
}edge[MAXM];
int head[MAXN];
int NV,NE,vs,vt; void addEdge(int u,int v,int cap,int cost){
edge[NE].u=u; edge[NE].v=v; edge[NE].cap=cap; edge[NE].cost=cost;
edge[NE].next=head[u]; head[u]=NE++;
edge[NE].u=v; edge[NE].v=u; edge[NE].cap=0; edge[NE].cost=-cost;
edge[NE].next=head[v]; head[v]=NE++;
}
bool vis[MAXN];
int d[MAXN],pre[MAXN];
bool SPFA(){
for(int i=0;i<NV;++i){
vis[i]=0;
d[i]=INF;
}
vis[vs]=1;
d[vs]=0;
queue<int> que;
que.push(vs);
while(!que.empty()){
int u=que.front(); que.pop();
for(int i=head[u]; i!=-1; i=edge[i].next){
int v=edge[i].v;
if(edge[i].cap && d[v]>d[u]+edge[i].cost){
d[v]=d[u]+edge[i].cost;
pre[v]=i;
if(!vis[v]){
vis[v]=1;
que.push(v);
}
}
}
vis[u]=0;
}
return d[vt]!=INF;
}
int MCMF(int tot){
int lastSum=0,lastTime=0;
while(SPFA()){
int flow=INF,cost=0;
for(int u=vt; u!=vs; u=edge[pre[u]].u){
flow=min(flow,edge[pre[u]].cap);
}
for(int u=vt; u!=vs; u=edge[pre[u]].u){
edge[pre[u]].cap-=flow;
edge[pre[u]^1].cap+=flow;
cost+=edge[pre[u]].cost;
} int time2=cost-lastTime,time1;
if(lastSum){
time1=tot/lastSum+(tot%lastSum!=0);
if(time1<=time2){
return lastTime+time1;
}
}
tot-=time2*lastSum;
tot-=flow;
if(tot<=0){
return cost;
}
lastTime=cost;
lastSum+=flow;
}
if(lastSum==0) return -1;
return lastTime+tot/lastSum+(tot%lastSum!=0);
} int main(){
int n,m,k;
while(~scanf("%d%d%d",&n,&m,&k)){
vs=0; vt=n-1; NV=n; NE=0;
memset(head,-1,sizeof(head));
int a,b,c;
while(m--){
scanf("%d%d%d",&a,&b,&c);
addEdge(a,b,c,1);
}
if(k==0){
puts("0");
continue;
}
int ans=MCMF(k);
if(ans==-1) puts("No solution");
else printf("%d\n",ans);
}
return 0;
}