题目
题目概要
n
n
n 个点、
m
m
m 条边的无向图,找一些点,使得删去这些点后,
a
a
a 和
b
b
b 不连通。最小化点权和。
数据范围与约定
2
≤
n
≤
200
,
1
≤
m
≤
20000
2\le n\le 200,1\le m\le 20000
2≤n≤200,1≤m≤20000 。
思路
错误思路:动态规划
什么?万能的DP竟然是错误思路?
用 f ( x ) f(x) f(x) 表示 x x x 不可达的最小费用。
满心以为, f ( x ) = min [ c x , ∑ ⟨ x , i ⟩ ∈ E f ( i ) ] f(x)=\min\left[c_x,\sum_{\langle x,i\rangle\in E}f(i)\right] f(x)=min[cx,∑⟨x,i⟩∈Ef(i)] 。
然而……我们并没有规定 f ( x ) f(x) f(x) 的定义域在哪里!
所以,一个点可能被 f ( y 1 ) , f ( y 2 ) f(y_1),f(y_2) f(y1),f(y2) 各计算一次。于是……稻花香里说丰年,听取 w a \tt wa wa 声一片……
如果你愿意,可以改成状压。
正确思路:网络流
似乎就是把这张图切开。那就求 最小割 吧!
如果我们控制了一个点,那么劫匪就“有进无回”。所以我们把一个点的入度、出度承载在两个点上,两个点之间的连边是点权。切掉这条边,就相当于“进去了就出不来了”。
然后求就行了。说起来, O ( V 2 E ) \mathcal O(V^2E) O(V2E) 的算法都能过?我用的 i s a p \tt{isap} isap 。
代码
#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
inline int readint(){ int x; scanf("%d",&x); return x; }
inline void writeint(long long x){ printf("%lld",x); }
const int MaxN = 505, infty = (1<<30)-1;
int c[MaxN][MaxN], n, m;
void addEdge(int from,int to,int val){
c[from][to] += val;
}
int started, ended;
void input(){
n = readint(), m = readint();
started = readint()-1, ended = readint()-1;
for(int i=0; i<n; ++i)
addEdge(i<<1,i<<1|1,readint());
for(int i=0,u,v; i<m; ++i){
u = readint()-1, v = readint()-1;
addEdge(u<<1|1,v<<1,infty);
addEdge(v<<1|1,u<<1,infty);
}
}
int d[MaxN], vd[MaxN];
int dfs(int x,int inFlow,const int &T){
if(x == T) return inFlow;
int sum = 0, minD = (n<<1)-1, delta;
for(int i=0; i<(n<<1); ++i)
if(c[x][i] > 0){
if(d[x] == d[i]+1){
delta = dfs(i,min(inFlow-sum,c[x][i]),T);
c[x][i] -= delta, c[i][x] += delta;
if((sum += delta) == inFlow) break;
if(d[T] == -1) return sum; /* over */
}
minD = min(minD,d[i]);
}
if(not sum){ /* 在G_f中没有出度 */
if((-- vd[d[x]]) == 0) d[T] = -1;
++ vd[d[x] = minD + 1];
}
return sum;
}
int isap(int s,int t){
int maxFlow = 0;
for(int i=0; i<(n<<1); ++i)
d[i] = vd[i] = 0;
for(vd[0]=(n<<1); ~d[t]; )
maxFlow += dfs(s,infty,t);
return maxFlow;
}
void solve(){
writeint(isap(started<<1,ended<<1|1));
putchar('\n');
}
int main(){
input(), solve();
return 0;
}