题目: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的点。
代码:
#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++