Destroying The Graph (poj 2125 最小点权覆盖)
来源:互联网 发布:招在家工作淘宝客服 编辑:程序博客网 时间:2024/05/17 02:18
Description
Alice assigns two costs to each vertex: Wi+ and Wi-. If Bob removes all arcs incoming into the i-th vertex he pays Wi+ dollars to Alice, and if he removes outgoing arcs he pays Wi- dollars.
Find out what minimal sum Bob needs to remove all arcs from the graph.
Input
Output
Sample Input
3 61 2 34 2 11 21 13 21 23 12 3
Sample Output
531 +2 -2 +
Source
题意:有一张有向图n个点m有向边,现在每次删除一个点的所有入边费用为W+,或者删除一个点的所有的出边费用为W-,问删除所有的边最小费用是多少。
思路:最小点权覆盖问题,具体贴上《最小割模型在信息学竞赛中的应用》中的阐述:
回顾与此模型相关的模型。简化权的条件后,可以借鉴的是二分图匹配的大流解法。 它加入了额外的源s和汇t,将匹配以一条条s->u->v->t形式的流路径“串联”起来。匹配的 限制是在点上,恰当地利用了流的容量限制。而点覆盖集的限制在边上,最小割是最大流的对偶问题,对偶往往是将问题的性质从点转边,从边转点。可以尝试着转化到最小割模型。 基于以上尝试动机,建立一个源s,向X 部每个点连边;建立一个汇t,从Y部每个点向汇t连边,把二分图中的边看成是有向的。则任意一条从s到t的路径,一定具有s->u->v->t的形式。割的性质是不存在一条从s到t的路径。故路径上的三条边(s,u),(u,v),(v,t)中至少有一条边在割中。若人为地令(u,v)不可能在最小割中,即令其容量为正无限c(u,v)=INF。则条件简化为(s,u),(v,t)中至少一条边在小割中,正好与点覆盖集限制条件的形式相符( u∈V`,v∈V`至少一个成立)。而目标是最小化点权之和,恰好也是最小割的优化目标。 形式化以上推理过程,将原问题的图G转化为网络N=(VN,EN)的最小割模型。 在原图点集的基础上增加源s和汇t:将每条二分图的边(u,v)∈E替换为容量为c(u,v)=∞的有向边 ,(u,v)∈ EN;增加源s到X部的点u的有向边(s,u) ∈ EN,容量即该点权值c(u,v)=Wu;增加Y部的点v到汇t的有向边(v,t)∈EN ,同样,容量为该点权值c(u,v)=Wv。
代码:
#include <iostream>#include <functional>#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>#include <string>#include <map>#include <stack>#include <vector>#include <set>#include <queue>#pragma comment (linker,"/STACK:102400000,102400000")#define pi acos(-1.0)#define eps 1e-6#define lson rt<<1,l,mid#define rson rt<<1|1,mid+1,r#define FRE(i,a,b) for(i = a; i <= b; i++)#define FREE(i,a,b) for(i = a; i >= b; i--)#define FRL(i,a,b) for(i = a; i < b; i++)#define FRLL(i,a,b) for(i = a; i > b; i--)#define mem(t, v) memset ((t) , v, sizeof(t))#define sf(n) scanf("%d", &n)#define sff(a,b) scanf("%d %d", &a, &b)#define sfff(a,b,c) scanf("%d %d %d", &a, &b, &c)#define pf printf#define DBG pf("Hi\n")typedef long long ll;using namespace std;#define INF 0x3f3f3f3f#define mod 1000000009const int maxn = 105;const int MAXN = 205;const int MAXM = 200010;struct Edge{ int to,next,cap,flow;}edge[MAXM];int n,m;int a[maxn],b[maxn];int tol;int head[MAXN];int gap[MAXN],dep[MAXN],pre[MAXN],cur[MAXN];void init(){ tol=0; memset(head,-1,sizeof(head));}//加边,单向图三个参数,双向图四个参数void addedge(int u,int v,int w,int rw=0){ edge[tol].to=v; edge[tol].cap=w; edge[tol].next=head[u]; edge[tol].flow=0; head[u]=tol++; edge[tol].to=u; edge[tol].cap=rw; edge[tol].next=head[v]; edge[tol].flow=0; head[v]=tol++;}//输入参数:起点,终点,点的总数//点的编号没有影响,只要输入点的总数int sap(int start,int end,int N){ memset(gap,0,sizeof(gap)); memset(dep,0,sizeof(dep)); memcpy(cur,head,sizeof(head)); int u=start; pre[u]=-1; gap[0]=N; int ans=0; while (dep[start]<N) { if (u==end) { int Min=INF; for (int i=pre[u];i!=-1;i=pre[edge[i^1].to]) if (Min>edge[i].cap-edge[i].flow) Min=edge[i].cap-edge[i].flow; for (int i=pre[u];i!=-1;i=pre[edge[i^1].to]) { edge[i].flow+=Min; edge[i^1].flow-=Min; } u=start; ans+=Min; continue; } bool flag=false; int v; for (int i=cur[u];i!=-1;i=edge[i].next) { v=edge[i].to; if (edge[i].cap-edge[i].flow && dep[v]+1==dep[u]) { flag=true; cur[u]=pre[v]=i; break; } } if (flag) { u=v; continue; } int Min=N; for (int i=head[u];i!=-1;i=edge[i].next) if (edge[i].cap-edge[i].flow && dep[edge[i].to]<Min) { Min=dep[edge[i].to]; cur[u]=i; } gap[dep[u]]--; if (!gap[dep[u]]) return ans; dep[u]=Min+1; gap[dep[u]]++; if (u!=start) u=edge[pre[u]^1].to; } return ans;}bool vis[MAXN];void dfs(int u){ vis[u]=true; for (int i=head[u];~i;i=edge[i].next) { int v=edge[i].to; if (edge[i].cap-edge[i].flow>0&&!vis[v]) { dfs(v); } }}int main(){#ifndef ONLINE_JUDGE freopen("C:/Users/lyf/Desktop/IN.txt","r",stdin);#endif int i,j,u,v; while (~scanf("%d%d",&n,&m)) { for (i=1;i<=n;i++) scanf("%d",&a[i]); for (i=1;i<=n;i++) scanf("%d",&b[i]); init(); for (i=0;i<m;i++) { scanf("%d%d",&u,&v); addedge(u,v+n,INF); } for (i=1;i<=n;i++) { addedge(0,i,b[i]); addedge(i+n,2*n+1,a[i]); } int ans=sap(0,2*n+1,2*n+2); printf("%d\n",ans); dfs(0); int num=0; vector<int>aa,bb; for (i=1;i<=n;i++) { if (!vis[i]) { aa.push_back(i); num++; } } for (i=n+1;i<=2*n;i++) { if (vis[i]) { bb.push_back(i-n); num++; } } printf("%d\n",num); for (i=0;i<aa.size();i++) { printf("%d -\n",aa[i]); } for (i=0;i<bb.size();i++) { printf("%d +\n",bb[i]); } } return 0;}
- Destroying The Graph (poj 2125 最小点权覆盖)
- POJ 2125 Destroying The Graph 最小点权覆盖
- POJ 2125 Destroying The Graph 最小点权覆盖集
- 【POJ】2125 Destroying The Graph 最小点权覆盖
- poj 2125 Destroying The Graph 最小点权覆盖
- poj 2125 Destroying The Graph 最小点权覆盖集
- poj 2125 Destroying The Graph(最小点权覆盖集)
- poj 2125 Destroying The Graph(最小割,最小点权覆盖)
- POJ 2125 Destroying The Graph (最小点权覆盖集)
- POJ 2125 Destroying The Graph 二分图最小点权覆盖 最小割
- POJ 2125 Destroying The Graph (dinic求最小点权覆盖)
- 【二分图|最小点权覆盖】POJ-2125 Destroying The Graph
- POJ 2125 Destroying The Graph(二分图最小点权覆盖)
- POJ 2125 Destroying The Graph 二分图最小点权覆盖集
- POJ 2125 Destroying The Graph 二分图 最小点权覆盖
- POJ 2125 Destroying The Graph 二分图 最小点权覆盖
- POJ 2125 Destroying The Graph 二分图 最小点权覆盖
- POJ 2125 Destroying The Graph 二分图 最小点权覆盖
- 美团面试失败总结
- 1/ 向上转型
- python基础之五种数据类型--2
- IOS征途之三 分类与协议(二)
- mac下 eclipse+hadoop2.6.0完全配置,实例验证
- Destroying The Graph (poj 2125 最小点权覆盖)
- python基础教程
- shell如何将文本文件字符串换行后转换为数组
- C++容器deque
- 解决properties文件乱码问题
- Fire Game [kuangbin带你飞]专题一 简单搜索
- C语言 输入n,分别用*输出边长为n的实心菱形和空心菱形
- hdoj-1724 Ellipse(自适应Simpson积分)
- android捕获全局异常