最大流ISAP模板
#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 () ) ;
}
}
题意:囧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
*/
题意:给出一个矩形的长宽,每一行的和,每一列的和(题目并不是直接给出,稍微转换下),还原出该矩形,矩阵上的任一元素大于等于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 ( "" ) ;
}
}
}
uva11167 - Monkeys in the Emei Mountain
题意:有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
*/