• 题意: 最小割
  • 思路: 点权为1,边权无限,要把点拆为出点和入点,由于指定了源点和汇点且源点汇点不能被割掉,超级源要连源点的出点,超级汇要连汇的入点。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
typedef  pair<int,int> pii;
const int N = 2000;
const int INF = 0x3f3f3f3f;

struct E{
    int u,v,flow,nxt;
    E(){}
    E(int u,int v,int flow,int nxt):u(u),v(v),flow(flow),nxt(nxt){}
}e[N*2];

int n,m,sp,tp,tot;
int head[N],dis[N],pre[N],cur[N];
void init(){
    tot = 0;    memset(head,-1,sizeof head);
}
void addE(int u,int v,int flow){
    e[tot].u = u; e[tot].v = v; e[tot].flow = flow; e[tot].nxt = head[u]; head[u] = tot++;
    e[tot].u = v; e[tot].v = u; e[tot].flow = 0; e[tot].nxt = head[v]; head[v] = tot++;
}
int q[N];
int bfs(){
    int qtop = 0,qend=0;
    memset(dis,-1,sizeof dis);
    dis[sp] = 0;
    q[qend++] = sp;
    while(qtop!=qend){
        int u = q[qtop++];
        if(u==tp)   return true;
        for(int i=head[u];~i;i=e[i].nxt){
            int v = e[i].v;
            if(dis[v]==-1 && e[i].flow){
                dis[v] = dis[u]+1;
                q[qend++] = v;
            }
        }
    }
    return dis[tp]!=-1;
}
int dfs(int u,int flow){
    int res = 0;
    if(u==tp)   return flow;
    for(int i=head[u];i!=-1&&flow;i=e[i].nxt){
        int v = e[i].v;
        if(dis[v]==dis[u]+1 && e[i].flow){
            int d = dfs(v,min(e[i].flow,flow));
            e[i].flow -=d;
            e[i^1].flow += d;
            res+=d;
            flow -= d;
        }
    }
    if(!res)
        dis[u] = -2;
    return res;
}
int dinic(){
    int ans=0;
    while(bfs()){
        ans+=dfs(sp,INF);
    }
    return ans;
}
int main(){
    int c1,c2;
    scanf("%d%d%d%d",&n,&m,&c1,&c2);
    sp = n*2 +1 , tp = sp +1;
    int u,v;
    init();
    addE(sp,c1+n,INF);
    addE(c2,tp,INF);

    for(int i=1;i<=n;++i)   addE(i,i+n,1);
    for(int i=1;i<=m;++i){
        scanf("%d%d",&u,&v);
        addE(u+n,v,INF);
        addE(v+n,u,INF);
    }

    printf("%d\n",dinic());
    return 0;
}
02-01 03:34