最大流ISAP模板
poj1273
#include<stdio.h> #include<string.h> #include<algorithm> #include<queue> #define ll __int64 using namespace std ; const int maxn = 111111 ; struct Edge { int from , to , cap , flow , next ; } edge[maxn<<1] ; int head[maxn] , tot , s , t , n , m ; int dis[maxn] , vis[maxn] , num[maxn] , p[maxn] , cur[maxn] ; queue<int> Q ; int max ( int a , int b ) { return a > b ? a : b ; } int min ( int a , int b ) { return a < b ? a : b ; } void new_edge ( int a , int b , int c ) { edge[tot].to = b ; edge[tot].from = a ; edge[tot].cap = c ; edge[tot].flow = 0 ; edge[tot].next = head[a] ; head[a] = tot ++ ; } void bfs () { Q.push ( t ) ; vis[t] = 1 ; while ( !Q.empty () ) { int u = Q.front () ; Q.pop () ; int i ; for ( i = head[u] ; i != -1 ; i = edge[i].next ) { Edge e = edge[i] ; if ( !e.cap && !vis[e.to] ) { vis[e.to] = 1 ; dis[e.to] = dis[u] + 1 ; Q.push ( e.to ) ; } } } } int arg () { int x = t , ret = 111111111 ; while ( x != s ) { ret = min ( ret , edge[p[x]].cap - edge[p[x]].flow ) ; x = edge[p[x]].from ; } x = t ; while ( x != s ) { edge[p[x]].flow += ret ; edge[p[x]^1].flow -= ret ; x = edge[p[x]].from ; } return ret ; } ll max_flow () { ll flow = 0 ; int x = s , i ; bfs () ; for ( i = 1 ; i <= n ; i ++ ) num[dis[i]] ++ , cur[i] = head[i] ; while ( dis[s] < n ) { if ( x == t ) { flow += (ll) arg () ; x = s ; } int ok = 0 ; for ( i = cur[x] ; i != -1 ; i = edge[i].next ) { Edge e = edge[i] ; if ( e.cap > e.flow && dis[x] > dis[e.to] ) { ok = 1 ; cur[x] = i ; p[e.to] = i ; x = e.to ; break ; } } if ( !ok ) { int m = n - 1 , i ; for ( i = head[x] ; i != -1 ; i = edge[i].next ) { Edge e = edge[i] ; if ( e.cap > e.flow ) m = min ( m , dis[e.to] ) ; } if ( --num[dis[x]] == 0 ) break ; num[dis[x]=m+1] ++ ; cur[x] = head[x] ; if ( x != s ) x = edge[p[x]].from ; } } return flow ; } void init ( int n ) { int i ; for ( i = 0 ; i <= n ; i ++ ) { cur[i] = dis[i] = vis[i] = num[i] = 0 ; head[i] = -1 ; } tot = 0 ; while ( !Q.empty () ) Q.pop () ; } int main () { int a , b , c ; while ( scanf ( "%d%d" , &m , &n ) != EOF ) { init ( n ) ; s = 1 , t = n ; while ( m -- ) { scanf ( "%d%d%d" , &a , &b , &c ) ; new_edge ( a , b , c ) ; new_edge ( b , a , 0 ) ; } printf ( "%I64d\n" , max_flow () ) ; } }
poj1149 PIGS
题意:囧king有M个猪圈,猪圈i中有num[i]头猪,但很囧的是,囧king没钥匙,钥匙都在顾客那里。之后n天中,每天会来一个顾客,他会打开其中的k个猪圈,从中挑出a头猪,挑完后,k个猪圈中的猪可以被重新安排,然后猪圈的们都会被关上,问囧king最多能卖出多少猪。
解题思路:囧king说是最大流。。i从1到n,建边(s,i )其容量是所有i能开的猪圈,但还没被其他人开过的猪圈里的猪的总和。若有已经被开过的猪圈,设上一次开这个猪圈的人为x,则建边(x,i),容量为INF,并将上一次开这个猪圈的人更新为i。最后从1到n,建边(i,t)容量为i的购买力。其原理可以理解为,能直接流到i的猪为未被开过的猪圈里的猪,而若有猪圈已经被开过了,那能流到上一个人的猪全都可以流到i这里。最后从i这个人只能流出他的购买力。
#include<stdio.h> #include<string.h> #include<algorithm> #include<vector> #include<queue> using namespace std ; const int INF = INT_MAX >> 1 ; const int maxn = 211111 ; int max ( int a , int b ) { return a > b ? a : b ; } int min ( int a , int b ) { return a < b ? a : b ; } struct Edge { int from , to , cap , flow , next ; } edge[maxn<<1] ; int head[maxn] , tot ; int s , t , n ; void new_edge ( int a , int b , int c ) { edge[tot].from = a ; edge[tot].to = b ; edge[tot].cap = c ; edge[tot].flow = 0 ; edge[tot].next = head[a] ; head[a] = tot ++ ; } struct ISAP { int cur[maxn] , dis[maxn] , p[maxn] , num[maxn] , vis[maxn] ; queue<int> Q ; void bfs () { while ( !Q.empty () ) Q.pop () ; int u , v , i ; Q.push ( t ) ; vis[t] = 1 ; while ( !Q.empty () ) { u = Q.front () , Q.pop () ; for ( i = head[u] ; i != -1 ; i = edge[i].next ) { int v = edge[i].to ; if ( edge[i].cap == 0 && !vis[v] ) { Q.push ( v ) ; dis[v] = dis[u] + 1 ; vis[v] = 1 ; } } } } int arg () { int ret = INF , x = t ; while ( x != s ) { ret = min ( ret , edge[p[x]].cap - edge[p[x]].flow ) ; x = edge[p[x]].from ; } x = t ; while ( x != s ) { edge[p[x]].flow += ret ; edge[p[x]^1].flow -= ret ; x = edge[p[x]].from ; } return ret ; } int max_flow () { bfs () ; int i , x = s , flow = 0 ; for ( i = 1 ; i <= n ; i ++ ) num[dis[i]] ++ , cur[i] = head[i] ; while ( dis[s] < n ) { if ( x == t ) { flow += arg () ; x = s ; } int ok = 0 ; for ( i = cur[x] ; i != -1 ; i = edge[i].next ) { Edge e = edge[i] ; if ( e.cap > e.flow && dis[e.to] < dis[x] ) { ok = 1 , cur[x] = i , p[e.to] = i , x = e.to ; break ; } } if ( !ok ) { int m = n - 1 ; for ( i = head[x] ; i != -1 ; i = edge[i].next ) { if ( edge[i].cap > edge[i].flow ) m = min ( m , dis[edge[i].to] ) ; } if ( --num[dis[x]] == 0 ) break ; num[dis[x]=m+1] ++ ; cur[x] = head[x] ; if ( x != s ) x = edge[p[x]].from ; } } return flow ; } void init () { int i ; for ( i = 0 ; i <= n ; i ++ ) { dis[i] = num[i] = vis[i] = 0 ; head[i] = -1 ; } tot = 0 ; } } sap ; int num[maxn] , to[maxn] ; int main () { int i , a , b , c , j , m ; while ( scanf ( "%d%d" , &m , &n ) != EOF ) { n += 2 ; sap.init () ; s = n , t = n - 1 ; for ( i = 1 ; i <= m ; i ++ ) scanf ( "%d" , &num[i] ) , to[i] = 0 ; for ( i = 1 ; i <= n - 2 ; i ++ ) { int k ; scanf ( "%d" , &k ) ; int add = 0 ; while ( k -- ) { scanf ( "%d" , &a ) ; if ( to[a] == 0 ) { add += num[a] ; to[a] = i ; } else { int x = to[a] ; to[a] = i ; new_edge ( x , i , INF ) ; new_edge ( i , x , 0 ) ; } } if ( add ) new_edge ( s , i , add ) , new_edge ( i , s , 0 ) ; scanf ( "%d" , &a ) ; if ( a ) new_edge ( i , t , a ) , new_edge ( t , i , 0 ) ; } printf ( "%d\n" , sap.max_flow () ) ; } } /* 3 3 3 1 3 2 1 2 1 2 2 3 1 1 2 5 ans = 7 */
uva11082 Matrix Decompressing
题意:给出一个矩形的长宽,每一行的和,每一列的和(题目并不是直接给出,稍微转换下),还原出该矩形,矩阵上的任一元素大于等于1,小于等于20。题目保证至少有一个解,输出任一解。
解题思路:最大流。。每一行,每一列分别为一个节点,再设一个起点,一个终点。起点向行节点建边,容量为该行的和减去列数(保证每个元素至少为1,即图上已经有(m*n)的流量流过),列节点向终点建边,容量为该列的和减去行数(也是为了保证每个元素至少为1)。行节点向列节点建边,容量为19(因为每条边上已经有1的流量流过)。最大流流一遍后,行节点指向列节点的边上的流量+1即为矩阵上每个元素的值。
#include<stdio.h> #include<string.h> #include<algorithm> #include<queue> using namespace std ; const int maxn = 111111 ; int min ( int a , int b ) { return a < b ? a : b ;} struct Edge { int from , to , cap , flow , next ; } edge[maxn] ; int head[maxn] , tot , s , t , n ; void new_edge ( int a , int b , int c ) { edge[tot].from = a ; edge[tot].to = b ; edge[tot].cap = c ; edge[tot].flow = 0 ; edge[tot].next = head[a] ; head[a] = tot ++ ; } struct ISAP { int vis[maxn] , p[maxn] , num[maxn] , dis[maxn] , cur[maxn] ; queue<int> Q ; void init ( int n ) { while ( !Q.empty () ) Q.pop () ; int i ; for ( i = 0 ; i <= n ; i ++ ) { vis[i] = num[i] = dis[i] = 0 ; head[i] = -1 ; } tot = 0 ; } void bfs () { int u , v , i ; Q.push ( t ) ; vis[t] = 1 ; while ( !Q.empty () ) { u = Q.front () , Q.pop () ; for ( i = head[u] ; i != -1 ; i = edge[i].next ) if ( !edge[i].cap && !vis[edge[i].to] ) { Q.push ( edge[i].to ) , vis[edge[i].to] = 1 ; dis[edge[i].to] = dis[u] + 1 ; } } } int arg () { int ret = 111111 , x = t ; while ( x != s ) { ret = min ( ret , edge[p[x]].cap - edge[p[x]].flow ) ; x = edge[p[x]].from ; } x = t ; while ( x != s ) { edge[p[x]].flow += ret ; edge[p[x]^1].flow -= ret ; x = edge[p[x]].from ; } return ret ; } int max_flow () { bfs () ; int x = s , i , flow = 0 ; for ( i = 1 ; i <= n ; i ++ ) num[dis[i]] ++ , cur[i] = head[i] ; while ( dis[s] < n ) { if ( x == t ) x = s , flow += arg () ; int ok = 0 ; for ( i = cur[x] ; i != -1 ; i = edge[i].next ) { Edge e = edge[i] ; if ( e.cap > e.flow && dis[e.to] < dis[x] ) { ok = 1 , cur[x] = i , p[e.to] = i , x = e.to ; break ; } } if ( !ok ) { int m = n - 1 ; for ( i = head[x] ; i != -1 ; i = edge[i].next ) if ( edge[i].cap > edge[i].flow ) m = min ( m , dis[edge[i].to]) ; if ( -- num[dis[x]] == 0 ) break ; num[dis[x]=m+1] ++ ; cur[x] = head[x] ; if ( x != s ) x = edge[p[x]].from ; } } return flow ; } } sap; int ret[888][888] , num[888] ; int main () { int m , i , j , k ; int ca = 0 , cas ; scanf ( "%d" , &cas ) ; while ( cas -- ) { scanf ( "%d%d" , &m , &n ) ; n += m + 2 ; sap.init ( n ) ; s = n - 1 , t = n ; for ( i = 1 ; i <= m ; i ++ ) scanf ( "%d" , &num[i] ) ; for ( i = m ; i >= 1 ; i -- ) num[i] -= ( ( n - m - 2 ) + ( i == 1 ? 0 : num[i-1] ) ) ; for ( i = m + 1 ; i <= n - 2 ; i ++ ) scanf ( "%d" , &num[i] ) ; for ( i = n - 2 ; i >= m + 1 ; i -- ) num[i] -= ( m + ( i == m + 1 ? 0 : num[i-1] ) ) ; for ( i = 1 ; i <= m ; i ++ ) { new_edge ( s , i , num[i] ) ; new_edge ( i , s , 0 ) ; } for ( i = m + 1 ; i <= n - 2 ; i ++ ) { new_edge ( i , t , num[i] ) ; new_edge ( t , i , 0 ) ; } for ( i = 1 ; i <= m ; i ++ ) for ( j = m + 1 ; j <= n - 2 ; j ++ ) { new_edge ( i , j , 19 ) ; new_edge ( j , i , 0 ) ; } sap.max_flow () ; for ( i = 1 ; i <= m ; i ++ ) for ( j = head[i] ; j != -1 ; j = edge[j].next ) if ( edge[j].cap ) ret[i][edge[j].to] = edge[j].flow + 1 ; printf ( "Matrix %d\n" , ++ca ) ; for ( i = 1 ; i <= m ; i ++ ) { for ( j = m + 1 ; j <= n - 2 ; j ++ ) { if ( j != m + 1 ) putchar ( ' ' ) ; printf ( "%d" , ret[i][j] ) ; } puts ( "" ) ; } } }
题意:有n只猴子要喝水,每只猴子只能在(a,b)时间段内喝v单位的水,不能多也不能少,也不能再其他时间段喝,每单位时间喝一单位水。而水源在同一单位时间能只能供m只猴子喝,问能否满足猴子们的要求,若能,输出每只猴子喝水的时间段。
解题思路:最大流。。可以想到暴力的建图方法,每个单位时间为一个节点,每只猴子也为一个节点,那么每个时间节点向它能供给的猴子建一条边,容量为1。源点向时间节点建边,容量为m。猴子向汇点建边,容量为v[i]。图上流过的最大流即为所有猴子所能喝的最多的水,若最大流等于猴子需求的水的总量,则能满足要求,否则不能(因为猴子向终点建的边的上限为猴子所能喝的水)。时间节点流向猴子的边上的流量即为该时间点该猴子喝的水(为0则不喝,为1则喝)。这是暴力的求解方法,时间复杂度太高,不可取。但这幅图还可以优化,我们并不需要每个时间点建一个节点,而只需要将猴子喝水的时间的交叉段全都分开来建节点,每一段一个节点。设时间段i的间隔为l[i],源点向时间段节点建边,容量为l[i] * m , 时间段节点向能在该时间段喝水的猴子建边,容量为l[i]。每只猴子向汇点建边,容量为v[i]。最大流流一遍后,是否有解同上。把每个时间段流量猴子的流量都取出来,暴力寻找猴子的喝水时间段即可。
#include<stdio.h> #include<string.h> #include<algorithm> #include<queue> using namespace std ; const int maxn = 111111 ; int min ( int a , int b ) { return a < b ? a : b ;} struct Edge { int from , to , cap , flow , next ; } edge[maxn] ; int head[maxn] , tot , s , t , n ; void new_edge ( int a , int b , int c ) { edge[tot].from = a ; edge[tot].to = b ; edge[tot].cap = c ; edge[tot].flow = 0 ; edge[tot].next = head[a] ; head[a] = tot ++ ; } struct ISAP { int vis[maxn] , p[maxn] , num[maxn] , dis[maxn] , cur[maxn] ; queue<int> Q ; void init () { while ( !Q.empty () ) Q.pop () ; int i ; for ( i = 0 ; i <= n ; i ++ ) { vis[i] = num[i] = dis[i] = 0 ; head[i] = -1 ; } tot = 0 ; } void bfs () { int u , v , i ; Q.push ( t ) ; vis[t] = 1 ; while ( !Q.empty () ) { u = Q.front () , Q.pop () ; for ( i = head[u] ; i != -1 ; i = edge[i].next ) if ( !edge[i].cap && !vis[edge[i].to] ) { Q.push ( edge[i].to ) , vis[edge[i].to] = 1 ; dis[edge[i].to] = dis[u] + 1 ; } } } int arg () { int ret = 111111 , x = t ; while ( x != s ) { ret = min ( ret , edge[p[x]].cap - edge[p[x]].flow ) ; x = edge[p[x]].from ; } x = t ; while ( x != s ) { edge[p[x]].flow += ret ; edge[p[x]^1].flow -= ret ; x = edge[p[x]].from ; } return ret ; } int max_flow () { bfs () ; int x = s , i , flow = 0 ; for ( i = 1 ; i <= n ; i ++ ) num[dis[i]] ++ , cur[i] = head[i] ; while ( dis[s] < n ) { if ( x == t ) x = s , flow += arg () ; int ok = 0 ; for ( i = cur[x] ; i != -1 ; i = edge[i].next ) { Edge e = edge[i] ; if ( e.cap > e.flow && dis[e.to] < dis[x] ) { ok = 1 , cur[x] = i , p[e.to] = i , x = e.to ; break ; } } if ( !ok ) { int m = n - 1 ; for ( i = head[x] ; i != -1 ; i = edge[i].next ) if ( edge[i].cap > edge[i].flow ) m = min ( m , dis[edge[i].to]) ; if ( -- num[dis[x]] == 0 ) break ; num[dis[x]=m+1] ++ ; cur[x] = head[x] ; if ( x != s ) x = edge[p[x]].from ; } } return flow ; } } sap; struct Monkey { int a , b , v ; } mon[maxn] ; struct Ans { int a , b ; bool operator < ( const Ans &p ) const { return a < p.a ; } } ; vector<Ans> vec[maxn] ; int x[1111] , y[1111] ; int num[maxn] ; int main () { int m , i , j , k , sum , ca = 0 ; while ( scanf ( "%d" , &n ) != EOF ) { if ( n == 0 ) break ; k = n ; sum = 0 ; int T = 0 ; scanf ( "%d" , &m ) ; for ( i = 1 ; i <= n ; i ++ ) { scanf ( "%d%d%d" , &mon[i].v , &mon[i].a , &mon[i].b ) ; num[++T] = mon[i].a ; num[++T] = mon[i].b ; sum += mon[i].v ; } sort ( num + 1 , num + T + 1 ) ; T = unique ( num + 1 , num + T + 1 ) - num - 1 ; sort ( num + 1 , num + T + 1 ) ; n = T + 2 + n ; s = n - 1 , t = n ; sap.init () ; for ( i = 2 ; i <= T ; i ++ ) { new_edge ( s , i , m * ( num[i] - num[i-1] ) ) ; new_edge ( i , s , 0 ) ; for ( j = 1 ; j <= k ; j ++ ) { if ( mon[j].a <= num[i-1] && mon[j].b >= num[i] ) { new_edge ( i , T + j , num[i] - num[i-1] ) ; new_edge ( T + j , i , 0 ) ; } } } for ( i = 1 ; i <= k ; i ++ ) { new_edge ( i + T , t , mon[i].v ) ; new_edge ( t , i + T , 0 ) ; } int fuck = sap.max_flow () ; for ( i = 1 ; i <= n ; i ++ ) vec[i].clear () ; printf ( "Case %d: " , ++ ca ) ; if ( fuck < sum ) puts ( "No" ) ; else { puts ( "Yes" ) ; for ( i = 2 ; i <= T ; i ++ ) { int last = num[i-1] ; for ( j = head[i] ; j != -1 ; j = edge[j].next ) { Edge e = edge[j] ; if ( e.flow > 0 ) { Ans u , p ; int v = e.to ; if ( last + e.flow > num[i] ) { u.a = last , u.b = num[i] ; vec[v].push_back ( u ) ; e.flow = ( last + e.flow - num[i] ) ; last = num[i-1] ; } u.a = last , u.b = last + e.flow ; last += e.flow ; vec[v].push_back ( u ) ; if ( last >= num[i] ) last = num[i-1] ; } } } for ( i = 1 ; i <= k ; i ++ ) { sort ( vec[T+i].begin () , vec[T+i].end () ) ; int l = vec[T+i].size () ; int add = 0 ; x[++add] = vec[T+i][0].a , y[add] = vec[T+i][0].b ; for ( j = 1 ; j < l ; j ++ ) { if ( vec[T+i][j].a == vec[T+i][j-1].b ) y[add] = vec[T+i][j].b ; else x[++add] = vec[T+i][j].a , y[add] = vec[T+i][j].b ; } printf ( "%d" , add ) ; for ( j = 1 ; j <= add ; j ++ ) printf ( " (%d,%d)" , x[j] , y[j] ) ; puts ( "" ) ; } } } } /* 3 2 2 1 10 9 1 10 7 1 10 */