网络流问题的常见套路
来源:互联网 发布:湖北大学知行学院宿舍 编辑:程序博客网 时间:2024/05/17 19:23
本文在接下来的一段时间内可能会经常扩充或修改,如有谬误敬请谅解。[2017.11.24]
“拆点”
拆点,顾名思义,就是把一个点拆成两个点。因为在网络流的模型中,割特指边集而非点集,所以想要实现“可以被割掉的点”,就用用到拆点思想。另外,这种方法也可以被理解为:使点同边一样有一个容量上限。
把点A分成两个,一个叫A1,表示A的“入点”;另一个叫A2,表示A的“出点”。A的所有出边都从A2连出,所有入边都连向A1。再连一条边从A1指向A2,其边权为点A的“点容量”。
例题:[USACO5.4]奶牛的电信(copy from 洛谷,特此表示感谢)
P1345 [USACO5.4]奶牛的电信Telecowmunication
题目描述
农夫约翰的奶牛们喜欢通过电邮保持联系,于是她们建立了一个奶牛电脑网络,以便互相交流。这些机器用如下的方式发送电邮:如果存在一个由c台电脑组成的序列a1,a2,…,a(c),且a1与a2相连,a2与a3相连,等等,那么电脑a1和a(c)就可以互发电邮。
很不幸,有时候奶牛会不小心踩到电脑上,农夫约翰的车也可能碾过电脑,这台倒霉的电脑就会坏掉。这意味着这台电脑不能再发送电邮了,于是与这台电脑相关的连接也就不可用了。
有两头奶牛就想:如果我们两个不能互发电邮,至少需要坏掉多少台电脑呢?请编写一个程序为她们计算这个最小值。
以如下网络为例:
1*
/ 3 - 2*
这张图画的是有2条连接的3台电脑。我们想要在电脑1和2之间传送信息。电脑1与3、2与3直接连通。如果电脑3坏了,电脑1与2便不能互发信息了。
输入输出格式
输入格式: 第一行
四个由空格分隔的整数:N,M,c1,c2.N是电脑总数(1<=N<=100),电脑由1到N编号。M是电脑之间连接的总数(1<=M<=600)。最后的两个整数c1和c2是上述两头奶牛使用的电脑编号。连接没有重复且均为双向的(即如果c1与c2相连,那么c2与c1也相连)。两台电脑之间至多有一条连接。电脑c1和c2不会直接相连。第2到M+1行 接下来的M行中,每行包含两台直接相连的电脑的编号。
输出格式: 一个整数表示使电脑c1和c2不能互相通信需要坏掉的电脑数目的最小值。
输入输出样例
样例输入:
3 2 1 2
1 3
2 3
样例输出:
1
附上代码
#include<cstdio>#include<cstdlib>#include<algorithm>#include<vector>#include<queue>#include<cstring>using namespace std;const int maxn=605,INF=0x3f3f3f3f;struct Dinic{ int n,s,t; struct Edge{ int from,to,cap,flow; }; vector<int>G[maxn]; vector<Edge>edges; int cur[maxn],d[maxn]; bool vis[maxn]; void addedge(int f,int t,int c){ edges.push_back((Edge){f,t,c,0}); edges.push_back((Edge){t,f,0,0}); int m=edges.size(); G[f].push_back(m-2); G[t].push_back(m-1); } bool BFS(){ //memset(d,0,sizeof(d)); memset(vis,0,sizeof(vis)); queue<int>Q; Q.push(s);d[s]=0;vis[s]=1; while(!Q.empty()){ int x=Q.front();Q.pop(); for(int i=0;i<G[x].size();i++){ Edge& e=edges[G[x][i]]; if(!vis[e.to] && e.cap>e.flow){ vis[e.to]=1; d[e.to]=d[x]+1; Q.push(e.to); } } } return vis[t]; } int DFS(int x,int a){ if(x==t || a==0)return a; int flow=0,f; for(int& i=cur[x];i<G[x].size();i++){ Edge& e=edges[G[x][i]]; if(e.cap>e.flow && d[e.to]==d[x]+1 && (f=DFS(e.to,min(a,e.cap-e.flow)))>0){ e.flow+=f; edges[G[x][i]^1].flow-=f; flow+=f; a-=f; if(a==0)break; } } return flow; } int MaxFlow(int S,int T){ s=S;t=T;int flow=0; while(BFS()){ memset(cur,0,sizeof(cur)); flow+=DFS(S,INF); } return flow; }}dinic;int main(){ int N,M,c1,c2;scanf("%d%d%d%d",&N,&M,&c1,&c2); for(int i=1;i<=N;i++){ dinic.addedge(i,i+N,1); } for(int i=1;i<=M;i++){ int x,y;scanf("%d%d",&x,&y); dinic.addedge(x+N,y,INF); dinic.addedge(y+N,x,INF); } int mf=dinic.MaxFlow(c1+N,c2); printf("%d\n",mf); return 0;}
本题求至少要删除多少个点使C1、C2不连通,问题的实质是一个最小割,跑一个最大流即可,因为只允许割点,不允许割边,所以原有的边边权都为INF。点权为1,表示每个点最多只能被删除一次。
- 网络流问题的常见套路
- 中小企业网络管理常见常见的问题
- 缓存超时删除常见的套路
- 常见的网络基本问题
- 线段树常见套路
- linux 网络常见的定义问题
- 如何定位 问题SQL的【一般套路】
- 面试常见的“套路”之--两个数的交换
- php面试题分享,破解常见的套路小招
- 常见网络问题汇总
- 常见网络编程问题
- 常见网络问题总结
- 常见网络问题
- 网络访问套路
- 网络访问套路
- 前端套路问题
- 常见的网上邻居访问问题汇集(网络摘抄)
- 网络管理常见的八个问题及解决
- 若相关程序员不幸逝世 他的开源软件会有人维护吗?
- MyBatis的分布查询延迟加载(select_resultMap)
- 【Educational Codeforces Round 33 B】Beautiful Divisors
- javascript引用类型(一)-------补充
- 【BZOJ1004】【HNOI2008】Cards 群论 置换 burnside引理 背包DP
- 网络流问题的常见套路
- 深入Redis主从高可用方案:哨兵机制核心原理
- log4j配置
- ES6尾部调用优化
- 浏览器地址相关知识
- 常用响应类型解释
- SEO正确的网站更新内容方案(二)
- grep 满足 或 排除多个关键字
- "Lexical or preprocessor issue"解决方法