给你一个有向图,每条边上都有每一时刻的最大流量,有k个人在点0,他们要去点n-1,问你最晚到达的那个人最快要多久。
思路:
这个题目做了很多次,用过费用流,也用过最大流,结果都不行,怎么说的,这道题目用该是借助费用流的找新路径去枚举,可以说是费用流变形吧,首先我们一定要明白一点,就是时间的影响,单纯的最大流如果在时间的基础上考虑没什么意义,而费用流呢,我们想象一下,如果把时间设成费用那么我们就可以吧流量和时间结合起来了,在费用流的过程中我们要知道,他每一次都是根据最短路去找新的路径的,也就是说路径在费用上来说是递增的(流量不一定),那么我们就可以根据这个特点来枚举一那些路径来过人,要明白,如果起点到终点有两条边,一条很近,一条很远,有可能大家都走近的路径(宁可排队走),也不走远的(所以直接最大流是错了),那么我们就可以枚举路径了,路径可以直接用费用流每次的路径,因为时间递增的,对于每一次我们能过的人是多少呢?这个地方很关键,对于每一条路径来说,如果当前的路径a距离是10,流量是15,那么当时间大于10的时候,每过一个时间单位,路径a都可以再过15个人,所以当前的时间段的总人数是
之前的总人数+(当前长度-上一个长度)* 上一个的总流量 + 当前流量
那么如果现在当前这一部之前的所有路径当路径要花费的时间是多少呢
now = 当前长度+剩余的路径长度/当前总流量 向上取整
这样比较now和ans更新答案就行了,还有一个地方要明确,就是当总人数超过全图的最大流的时候答案就是 费用流中最长的路径 + 总人数/全图最大流 向上取整,这个地方不用特判,上面的想法里面包括在这里,说了只是为了便于理解。
#include<stdio.h> #include<string.h> #include<queue> #include<math.h> #define N_node 2500 + 50 #define N_edge 10000 + 100 #define INF 2000000000 using namespace std; typedef struct { int from ,to ,next ,cost ,flow; }STAR; STAR E[N_edge]; int list[N_node] ,tot; int mer[N_edge] ,s_x[N_node]; void add(int a ,int b ,int c ,int d) { E[++tot].from = a; E[tot].to = b; E[tot].cost = c; E[tot].flow = d; E[tot].next = list[a]; list[a] = tot; } bool spfa(int s ,int t ,int n) { int mark[N_node] = {0}; for(int i = 0 ;i <= n ;i ++) s_x[i] = INF; queue<int>q; q.push(s); mark[s] = 1 ,s_x[s] = 0; memset(mer ,255 ,sizeof(mer)); while(!q.empty()) { int xin ,tou; tou = q.front(); q.pop(); mark[tou] = 0; for(int k = list[tou] ;k ;k = E[k].next) { xin = E[k].to; if(s_x[xin] > s_x[tou] + E[k].cost && E[k].flow) { s_x[xin] = s_x[tou] + E[k].cost; mer[xin] = k; if(!mark[xin]) { mark[xin] = 1; q.push(xin); } } } } return mer[t] != -1; } int M_C_Flow(int s ,int t ,int n ,int k) { if(!k) return 0; int minflow ,sum_peo = k ,now_peo = 0 ,list_time = 0 ,ans = INF; while(spfa(s ,t ,n)) { minflow = INF; for(int i = mer[t] ;i + 1 ;i = mer[E[i].from]) if(minflow > E[i].flow) minflow = E[i].flow; for(int i = mer[t] ;i + 1 ;i = mer[E[i].from]) E[i].flow -= minflow ,E[i^1].flow += minflow; sum_peo -= (s_x[t] - list_time) * now_peo + minflow; list_time = s_x[t] ,now_peo += minflow; int now = s_x[t] + (int)ceil((1.0 * (sum_peo < 0 ? 0 : sum_peo ))/now_peo); if(ans > now) ans = now; if(sum_peo < 1) break; } return ans; } int main () { int n ,m ,k ,i ,a ,b ,c; while(~scanf("%d %d %d" ,&n ,&m ,&k)) { memset(list ,0 ,sizeof(list)); tot = 1; for(i = 1 ;i <= m ;i ++) { scanf("%d %d %d" ,&a ,&b ,&c); a ++ ,b ++; add(a ,b ,1 ,c) ,add(b ,a ,-1 ,0); } int ans = M_C_Flow(1 ,n ,n ,k); ans == INF ? puts("No solution"):printf("%d " ,ans); } return 0; }