求无向图的点连通度(最少删除几个点,使得图不连通)
求最小割(最大流)。每个点只能被用一次,否则可能有多条增广路公用同一个点,而其实删掉这一个点就足够破坏这些路了。点只能用一次,想到拆点法。然后最大流算法就行了。
写了几个不同算法熟悉一下,结果ISAP的时候卡住了,怎么答案老不对,原来是由于用了拆点法n变成了2n。
#include
#include
#include
#include
#include
#define fi first
#define se second
#define pii pair
using namespace std;
const int INF = 0x3f3f3f3f;
typedef long long LL;
const int maxn = 500+10;
int n, m;
int u1[maxn], v1[maxn];
// 图
struct Edge{
int u, v, cap, flow;
Edge(int a, int b, int c, int d):u(a),v(b),cap(c),flow(d){}
};
vector edges;
vector G[maxn];
void addEdge(int u, int v, int cap){
edges.push_back(Edge(u,v,cap,0));
edges.push_back(Edge(v,u,0,0)); // 反向弧
int m = edges.size();
G[u].push_back(m-2);
G[v].push_back(m-1);
}
void init(){
for(int i = 0; i < maxn; ++i) G[i].clear();
edges.clear();
for(int i = 0; i < n; ++i) addEdge(i, i+n, 1);
for(int i = 0; i < m; ++i){
addEdge(u1[i]+n, v1[i], INF);
addEdge(v1[i]+n, u1[i], INF);
}
}
// ---------------- Q: ISAP 怎么了?
int Gap[maxn], cur[maxn], pre[maxn], dis[maxn];
void bfs(int s, int t){
memset(dis, -1, sizeof(dis));
memset(Gap, 0, sizeof(Gap));
dis[t] = 0;
Gap[0] = 1;
queue Q;
Q.push(t); // 反向
while(!Q.empty()){
int x = Q.front(); Q.pop();
for(int i = 0; i < G[x].size(); ++i){
Edge& e = edges[G[x][i]^1];
if(dis[e.u] == -1){
dis[e.u] = dis[x] + 1;
++Gap[dis[e.u]];
Q.push(e.u);
}
}
}
}
int augument(int s, int t){
int f = INF;
for(int u = t; u != s; u = edges[pre[u]].u){
Edge& e = edges[pre[u]];
f = min(f, e.cap - e.flow);
}
for(int u = t; u != s; u = edges[pre[u]].u){
edges[pre[u]].flow += f;
edges[pre[u]^1].flow -= f;
}
return f;
}
int ISAP(int s, int t){
bfs(s, t);
memset(cur, 0, sizeof(cur));
int u = s;
int ans = 0;
while(dis[s] < 2*n-2){ // 注意乘2!,-2是因为从出点到入点
if(u == t){
ans += augument(s, t);
u = s;
}
bool advanced = false;
for(int& i = cur[u]; i < G[u].size(); ++i){
Edge& e = edges[G[u][i]];
if(dis[u] == dis[e.v] + 1&&e.cap > e.flow){
pre[e.v] = G[u][i];
u = e.v;
advanced = true;
break;
}
}
if(!advanced){
int d = 2*n-3;
for(int i = 0; i < G[u].size(); ++i){
Edge& e = edges[G[u][i]];
if(e.cap > e.flow) d = min(d, dis[e.v]);
}
if(--Gap[dis[u]] == 0) break;
dis[u] = d + 1;
++Gap[dis[u]];
cur[u] = 0;
if(u != s) u = edges[pre[u]].u;
}
}
return ans;
}
int main()
{
//freopen("in.txt","r",stdin);
while(scanf("%d%d",&n,&m) == 2){
for(int i = 0; i < m; ++i)scanf(" (%d,%d)",&u1[i],&v1[i]);
int ans = INF;
for(int i = 1; i < n; ++i){
init();
ans = min(ans, ISAP(n, i));
//printf("%d -> %d, flow = %d\n",n,i,ans);
}
if(ans >= INF) ans = n;
printf("%d\n",ans);
}
return 0;
}