poj 2125 Destroying The Graph 最小割+方案输出
构图思路:
1.将所有顶点v拆成两个点, v1,v2
2.源点S与v1连边,容量为 W-
3.v2与汇点连边,容量为 W+
4.对图中原边( a, b ), 连边 (a1,b2),容量为正无穷大
则该图的最小割(最大流)即为最小花费。
简单证明: 根据ST割集的定义,将顶点分成两个点集。所以对于原图中的边(a,b),转换成 S->a1->b2->T. 则此时路径必定存在
一条割边,因为a1->b2为无穷大,所以割边必定是 S->a1 or b2->T, 若为前者则意味着删除a顶点的W-,后者则是b顶点的W+.
所以该图最小割即为最小花费。
计算方案: 对于构图后跑一次最大流,然后对于残留网络进行处理,首先从源点S出发,标记所有能访问到的顶点,这些顶点即为S割点集中
的顶点。 其他则为T集合中顶点, 然后从所有边中筛选出( A属于S,B属于T,且(A,B)容量为0 )的边,即为割边。因为我们的W+/W-边都只有一条,
且都分开了。比较容易处理。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<string>
#include<vector>
#include<algorithm>
using namespace std; const int MAXN = ;
const int MAXM = ;
const int inf = 0x3f3f3f3f;
int A[MAXN], B[MAXN];
struct Edge{
int u, v, f, nxt;
}edge[];
int head[MAXN], idx;
int n, m;
int S, T, N; void AddEdge(int u,int v,int f){
edge[idx].u = u, edge[idx].v = v, edge[idx].f = f;
edge[idx].nxt = head[u]; head[u] = idx++;
edge[idx].u = v, edge[idx].v = u, edge[idx].f = ;
edge[idx].nxt = head[v]; head[v] = idx++;
} int h[MAXN], vh[MAXN];
int dfs(int u,int flow){
if(u == T) return flow;
int tmp = h[u]+, sum = flow;
for(int i = head[u]; ~i; i = edge[i].nxt){
if( edge[i].f && (h[edge[i].v]+ == h[u]) ){
int p = dfs( edge[i].v, min(sum,edge[i].f));
edge[i].f-=p, edge[i^].f+=p, sum-=p;
if( sum== || h[S]==N ) return flow-sum;
}
}
for(int i = head[u]; ~i; i = edge[i].nxt)
if( edge[i].f ) tmp = min( tmp, h[edge[i].v] );
if( --vh[ h[u] ] == ) h[S] = N;
else ++vh[ h[u]=tmp+ ];
return flow-sum;
}
int sap(){
int maxflow = ;
memset(h,,sizeof(h));
memset(vh,,sizeof(vh));
vh[] = N;
while( h[S] < N ) maxflow += dfs( S, inf );
return maxflow;
} bool vis[MAXN];
int res[MAXM]; void DFS(int u ){
vis[u] = true;
for(int i = head[u]; ~i; i = edge[i].nxt ){
int v = edge[i].v;
if( !vis[v] && edge[i].f )
DFS( v );
}
}
void solve(){
int maxflow = sap();
printf("%d\n", maxflow );
memset( vis,,sizeof(vis));
DFS( S ); int cnt = ;
for(int i = ; i < idx; i += ){
int u = edge[i].u, v = edge[i].v;
if( vis[u] && !vis[v] && (edge[i].f == ) )
res[cnt++] = i;
}
printf("%d\n", cnt );
for(int i = ; i < cnt; i++ ){
int u = edge[ res[i] ].u, v = edge[ res[i] ].v;
if( u == S ) printf("%d -\n", v);
else printf("%d +\n", u-n );
}
} int main(){
while( scanf("%d%d",&n,&m) != EOF ){
S = , T = *n+, N = *n+; idx = ;
memset( head, -, sizeof(head)); for(int i = ; i <= n; i++ )
scanf("%d", &A[i]);
for(int i = ; i <= n; i++ )
scanf("%d", &B[i]);
int a, b;
for(int i = ; i < m; i++ ){
scanf("%d%d", &a,&b);
AddEdge( a, n+b, inf );
}
for(int i = ; i <= n; i++){
AddEdge( S, i, B[i] ); // - out
AddEdge( n+i, T, A[i] );// + in
}
solve();
}
return ;
}
poj 2125 Destroying The Graph 最小割+方案输出的更多相关文章
- POJ 2125 Destroying The Graph [最小割 打印方案]
Destroying The Graph Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 8311 Accepted: 2 ...
- POJ - 2125 Destroying The Graph (最小点权覆盖)
题意:给一张图,现在要删去所有的边,删去一个点的所有入边和所有出边都有其对应\(W_{i+}\)和\(W_{i-}\).求删去该图的最小花费,并输出解 分析:简而言之就是用最小权值的点集去覆盖所有的边 ...
- POJ 2125 Destroying The Graph (二分图最小点权覆盖集+输出最小割方案)
题意 有一个图, 两种操作,一种是删除某点的所有出边,一种是删除某点的所有入边,各个点的不同操作分别有一个花费,现在我们想把这个图的边都删除掉,需要的最小花费是多少. 思路 很明显的二分图最小点权覆盖 ...
- poj 2125 Destroying The Graph (最小点权覆盖)
Destroying The Graph http://poj.org/problem?id=2125 Time Limit: 2000MS Memory Limit: 65536K ...
- POJ 2125 Destroying the Graph 二分图最小点权覆盖
Destroying The Graph Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 8198 Accepted: 2 ...
- 图论(网络流,二分图最小点权覆盖):POJ 2125 Destroying The Graph
Destroying The Graph Description Alice and Bob play the following game. First, Alice draws some di ...
- POJ 2125 Destroying The Graph 二分图 最小点权覆盖
POJ2125 题意简述:给定一个有向图,要通过某些操作删除所有的边,每一次操作可以选择任意一个节点删除由其出发的所有边或者通向它的所有边,两个方向有不同的权值.问最小权值和的解决方案,要输出操作. ...
- ●POJ 2125 Destroying The Graph
题链: http://poj.org/problem?id=2125 题解: 最小割 + 输出割方案.建图:拆点,每个题拆为 i 和 i'分别表示其的入点和出点建立超源 S和超汇 T.S -> ...
- poj 3469 Dual Core CPU——最小割
题目:http://poj.org/problem?id=3469 最小割裸题. 那个限制就是在 i.j 之间连双向边. 根据本题能引出网络流中二元关系的种种. 别忘了写 if ( x==n+1 ) ...
随机推荐
- AES五种加密模式
分组密码在加密时明文分组的长度是固定的,而实用中待加密消息的数据量是不定的,数据格式可能是多种多样的.为了能在各种应用场合安全地使用分组密码,通常对不同的使用目的运用不同的工作模式. 一.电码本模式( ...
- 【RF库Collections测试】List Should Not Contain Duplicates
Name:List Should Not Contain DuplicatesSource:Collections <test library>Arguments:[ list_ | ms ...
- Linux init 命令
init命令用于切换到指定的运行级别,用法如下: [root@localhost ~]# init //关机 [root@localhost ~]# init //切换到单用户模式/救援模式 [roo ...
- 如何构建日均千万PV Web站点 (一)
其实大多数互联网网站起初的网站架构都是(Linux+Apache+MySQL+PHP). 不过随着时代的发展,科技的进步.互联网进入寻常百姓家的生活.所谓的用户的需求,铸就了一个个互联网大牛: htt ...
- Failed to resolve
一: 把//classpath 'com.android.tools.build:gradle:2.2.2'改成classpath 'com.android.tools.build:gradle:3. ...
- jinja语法
<!--base.html--> <!DOCTYPE html> <html lang="en"> <head> <!--ht ...
- java十年技术栈[总结复习用]
以下摘自http://www.tvtv223.com/so/8/default/8.html#36-数据库的分库分表mycat java技术栈 参考了众多资料,这里就不再详细列举了,可以自行去搜索 1 ...
- 【总结】redis和memcached的区别
1.Redis和Memcache都是将数据存放在内存中,都是内存数据库.不过memcache还可用于缓存其他东西,例如图片.视频等等: 2.Redis不仅仅支持简单的k/v类型的数据,同时还提供lis ...
- 【前端积累】javascript事件
什么是事件? 事件是一种异步编程的实现方式,本质上是程序各个组成部分之间的通信.就是文档或浏览器窗口发生的一些特定的交互瞬间(某种动作). 1.事件流 事件流描述的是从页面中接收事件的顺序. 1)事件 ...
- ndk编译android的lame库
1.lame c库: https://github.com/intervigilium/liblame 下载后解压,进入目录,terminal里运行ndk-build即可 2.lame android ...