Luogu P1345 https://www.luogu.com.cn/problem/P1345
很容易发现这题要求的是网络流中的最小割.
关于最小割, 我们有最大流最小割定理: 最小割的容量一定等于最大流的流量
但是这个定理是用于求最小割边, 而题目要求我们求的是最小割点.
那么这两个问题之间如何转化呢?
我们考虑把节点 \(p\) 拆成节点 \(p\) 和节点 \(p+n\), 入边连接到 \(p\), 出边连接到 \(p+n\), 在这之前连接一条权值为 \(1\) 的边, 删除这条边就相当于删除了这个点. 之所以权值为 \(1\), 是因为一个点只能被删除一次.
值得注意的是: 原图中的边边权应当置为无穷大, 因为题目对通信线路的流量并没有任何限制.
所以就可以跑一遍 \(Dinic\) 就可以愉快地 AC 了.
- #include
- #include
- using namespace std;
- struct data
- {
- int to,next,val;
- }e[4005];
- int head[4005],dis[4005],cur[4005],n,m,c1,c2,ans,cnt,u,v;
- void add(int u,int v,int w)
- {
- e[++cnt].to=v;
- e[cnt].next=head[u];
- head[u]=cnt;
- e[cnt].val=w;
- }
- bool bfs(int s,int t)
- {
- queue que;
- que.push(s);
- for (int i=1;i<=2*n;i++) dis[i]=0,cur[i]=head[i];
- dis[s]=1;
- while (!que.empty())
- {
- int u=que.front();
- que.pop();
- for (int i=head[u];i;i=e[i].next)
- {
- int v=e[i].to;
- if (e[i].val>0&&!dis[v])
- {
- dis[v]=dis[u]+1;
- if (v==t) return 1;
- que.push(v);
- }
- }
- }
- return 0;
- }
- int dfs(int u,int t,int flow)
- {
- if (u==t||!flow) return flow;
- int used=0;
- for (int i=cur[u];i;i=e[i].next)
- {
- cur[u]=i;
- int v=e[i].to;
- if (dis[u]+1!=dis[v]) continue;
- int tmp=dfs(v,t,min(flow-used,e[i].val));
- if (!tmp) continue;
- used+=tmp;
- e[i].val-=tmp;
- e[i^1].val+=tmp;
- if (flow-used==0) return flow;
- }
- return used;
- }
- void Dinic(int s,int t)
- {
- while (bfs(s,t)) ans+=dfs(s,t,0x3f3f3f3f);
- }
- int main()
- {
- scanf("%d%d%d%d",&n,&m,&c1,&c2);
- cnt=1;
- for (int i=1;i<=n;i++)
- {
- add(i,i+n,1),add(i+n,i,0);
- }
- for (int i=1;i<=m;i++)
- {
- scanf("%d%d",&u,&v);
- add(u+n,v,0x3f3f3f3f);
- add(v,u+n,0);
- add(v+n,u,0x3f3f3f3f);
- add(u,v+n,0);
- }
- Dinic(c1+n,c2);
- printf("%d",ans);
- return 0;
- }
来源: http://www.bubuko.com/infodetail-3327289.html