版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40924940/article/details/84335027
这道题 很有意思
这里的割不是线了 是点,这题比较麻烦的是建图
用一下网上大牛的图,附博客链接:https://www.luogu.org/space/show?uid=25630
有了这个图,整个题就显得简单很多了,
我们把一个点 拆成两个,一个是 i 另一个是 i + n ,这两点之间肯定先连上,之后对与一个点分成的两个点,我们去以此把无向图变成一个有向图,当然这道题里所有的边容量完全就是 无穷大 ,然后某点分成的两个点之间 边的容量设为 1 ,这样我们去割的时候计算出来的最小割就是我们要切断的点了,当然 别忘记反向边也需要初始化。需要注意的就是 我们输入 x y 的时候
链接的 是 x+n 和 y ,x 和 x+n 相连,起始点也不再是 s 而是 s + n了。。看图就感觉出来了。。。
然后根据最小割最大流相等,求一下最大流 就算出最小割了。
以下为 AC 代码
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int maxn = 2005;
const int INF = 0x3f3f3f3f;
int head[maxn*2],num;
struct node
{
int val;
int nex,to;
}ed[maxn*2];
void add(int u,int v,int w)
{
ed[++num].to = v;
ed[num].val = w;
ed[num].nex = head[u];
head[u] = num;
}
int h[maxn*2];
int st,en;
int n,m;
bool bfs()
{
queue<int> q;
memset(h,-1,sizeof(h));
h[st]=0,q.push(st);
while(q.size())
{
int u = q.front();
q.pop();
for(int i=head[u];i!=-1;i=ed[i].nex)
{
int v = ed[i].to;
if(h[v] == -1 && ed[i].val)
{
h[v] = h[u] + 1;
if(v == en)
return true;
q.push(v);
}
}
}
return false;
}
int dfs(int u, int val)
{
int add = 0;
if(u == en)
return val;
for(int i=head[u];i!=-1;i=ed[i].nex)
{
int v = ed[i].to;
if(h[v] == h[u] + 1 && ed[i].val)
{
int k = dfs(v, min(val - add, ed[i].val));
if(!k)
h[v] = -1;
add += k;
ed[i].val -= k;
ed[i ^ 1].val += k;
}
}
return add;
}
int dinic()
{
int ans = 0;
while(bfs())
{
ans += dfs(st, INF);
}
return ans;
}
int main()
{
cin>>n>>m>>st>>en;
st += n;
num = -1;
memset(head,-1,sizeof(head));
for(int i=1;i<=n;i++)
{
add(i, i+n, 1);
add(i+n, i, 0);
}
int x,y;
for(int i=1;i<=m;i++)
{
cin>>x>>y;
add(x+n, y, INF);
add(y, x+n, 0);
add(y+n, x, INF);
add(x, y+n, 0);
}
printf("%d\n",dinic());
return 0;
}