二分枚举租用飞机的最大花费,然后用小于等于最大花费的边构建层次图(依据时间)
构图思路: 利用二元组(x,y)表示 x天y城市
1. e天有飞机从a城市飞到b城市,能够承载x人,则添加单向边 ( e, a ) -> ( e+1, b ) 容量为x
2. 每一天的a城市到第二天的a城市连边,容量为正无穷大
3. 每一天的N城市到汇点T连边,容量为正无穷大
4. 源点V与第0天的所有顶点连边,容量为当前城市0天初始人数
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<string> #include<queue> #include<vector> using namespace std; const int M = 1010; const int inf = 0x3f3f3f3f; int n, d, m, tot; struct Fight{ int u, v; int c, p, e; void input(){ scanf("%d%d%d%d%d",&u,&v,&c,&p,&e); } }fight[M]; int people[35]; int S, T, N; struct Edge{ int v, f, nxt; }edge[250011]; int head[350], idx; void AddEdge(int u,int v,int f){ edge[idx].v = v, edge[idx].f = f; edge[idx].nxt = head[u], head[u] = idx++; edge[idx].v = u, edge[idx].f = 0; edge[idx].nxt = head[v], head[v] = idx++; } void CreateGraph(int Max){ //init idx = 0; memset( head, -1, sizeof(head)); S = 0, T = (d+1)*n+1, N = (d+1)*n+2; int u, v, c, p, e; for(int i = 0; i < m; i++){ u = fight[i].u, v = fight[i].v, c = fight[i].c, p = fight[i].p, e = fight[i].e; if( p <= Max ) AddEdge( e*n+u, (e+1)*n+v, c ); } for(int i = 1; i <= n; i++ ) AddEdge( S, i, people[i] ); for(int d1 = 0; d1 < d; d1++ ){ for(int i = 1; i <= n; i++ ) AddEdge( d1*n+i, (d1+1)*n+i, inf ); } for(int d1 = 0; d1 <= d; d1++ ) AddEdge( d1*n+n, T, inf ); } int h[400], vh[400]; int dfs(int u, int flow ){ if( u == T ) return flow; int t = h[u]+1, sum = flow; for(int i = head[u]; ~i; i = edge[i].nxt ){ int v = edge[i].v; if( edge[i].f && (h[v]+1==h[u]) ){ int tmp = dfs( v, min(sum,edge[i].f) ); edge[i].f -= tmp, edge[i^1].f += tmp; sum -= tmp; if( sum == 0 || h[S] == N ) return flow-sum; } } for(int i = head[u]; ~i; i = edge[i].nxt ) if( edge[i].f ) t = min( t, h[ edge[i].v ] ); if( --vh[ h[u] ] == 0 ) h[S] = N; else ++vh[ h[u] = t+1 ]; return flow - sum; } int sap(){ int maxflow = 0; memset( h, 0, sizeof(h)); memset( vh, 0, sizeof(vh)); vh[0] = N; while( h[S] < N ) maxflow += dfs( S, inf ); return maxflow; } int solve(){ int ans = -1; int l = 0, r = 100000; while( l <= r ){ int mid = (l+r)>>1; CreateGraph( mid ); int tmp = sap(); //printf("tmp = %d ", tmp); if( tmp >= tot ) ans = mid, r = mid-1; else l = mid+1; } return ans; } int main(){ int _; scanf("%d",&_); for(int Case = 1; Case <= _; Case++){ scanf("%d%d%d",&n,&d,&m); int u, v, c, p, e; for(int i = 0; i < m; i++) fight[i].input(); tot = 0; for(int i = 1; i <= n; i++){ scanf("%d", &people[i] ); tot += people[i]; } int ans = solve(); printf("Case #%d: ", Case ); if( ans == -1 ) puts("Impossible"); else printf("%d ", ans ); } return 0; }