BZOJ-2324: [ZJOI2011]营救皮卡丘(费用流)

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2324

怎么说呢?有点像餐巾计划的模型:

首先用Floyd预处理出可以到达i(0<=i<=n)节点的的所有点且不经过大于i的点的最短路,然后建模:

每个点拆成两个ui , vi(ui表示来源,vi表示去向):

然后我们每个据点(除了0)都之有意地经过一次(即不包括在最短路中的情况),那么连边(S , ui , 1 , 0)(表示从S(源点)连到ui一条容量为1费用为0的边),对于0,我们总共有k个人在该点出发,那么连(S , u0 , k , 0);

然后对于每个vi,连(vi , T , 1 ,0)

对于每一个点对(i,j),连(ui , vj , 1 , dist[ i ][ j ])dist[ i ][ j ]表示从i到j的最短路,且不经过大于j的点。

代码:

d50735fae6cd7b896312eaff0d2442a7d9330e54.jpg.png
#include 
#include 
#include 
 
using namespace std ;
 
#define MAXN 330
#define clear( t ) memset( t , 0 , sizeof( t ) )
#define inf 0x7fffffff
 
struct edge {
    edge *next , *pair ;
    int t , f , c ;
} *head[ MAXN ] ;
 
void Add( int s , int t , int f , int c ) {
    edge *p = new( edge ) ; 
    p -> t = t , p -> f = f , p -> c = c , p -> next = head[ s ] ;
    head[ s ] = p ;
}
 
void AddEdge( int s , int t , int f , int c ) {
    Add( s , t , f , c ) , Add( t , s , 0 , - c ) ;
    head[ s ] -> pair = head[ t ] , head[ t ] -> pair = head[ s ] ;
}
 
int node[ MAXN ][ 2 ] , V = 0 , S , T , n , m , K ;
int dis[ MAXN ][ MAXN ][ MAXN ] , Map[ MAXN ][ MAXN ] ;
 
void Floyd(  ) {
    for ( int k = 0 ; k <= n ; k ++ ) {
        for ( int i = 0 ; i <= n ; i ++ ) for ( int j = 0 ; j <= n ; j ++ ) {
            if ( Map[ i ][ k ] < inf && Map[ k ][ j ] < inf && i != j ) {
                Map[ i ][ j ] = min( Map[ i ][ k ] + Map[ k ][ j ] , Map[ i ][ j ] ) ;
            }
        }
        for ( int i = 0 ; i <= n ; i ++ ) for ( int j = 0 ; j <= n ; j ++ ) {
            dis[ k ][ i ][ j ] = Map[ i ][ j ] ;
        }
    }
}
 
int dist[MAXN];
bool f[MAXN];
int cost=0;
int slack[MAXN];
   
   
int aug(int v,int flow) {
    if (v==T) {
        cost+=flow*dist[S];
        return flow;
    }
    f[v]=false;
    int rec=0;
    for (edge *p=head[v];p;p=p->next) {
        if (f[p->t]&&p->f) {
            if (dist[v]==dist[p->t]+p->c) {
                int ret=aug(p->t,min(flow-rec,p->f));
                p->f-=ret,p->pair->f+=ret;
                if ((rec+=ret)==flow) return flow;
            } else slack[p->t]=min(slack[p->t],dist[p->t]-dist[v]+p->c);
        }
    }
    return rec;
}
   
bool relabel() {
    int delta=inf;
    for (int i=0;i++

你可能感兴趣的:(BZOJ-2324: [ZJOI2011]营救皮卡丘(费用流))