POJ 2125 Destroying The Graph 二分图 最小点权覆盖
题意简述:给定一个有向图,要通过某些操作删除所有的边,每一次操作可以选择任意一个节点删除由其出发的所有边或者通向它的所有边,两个方向有不同的权值。问最小权值和的解决方案,要输出操作。
乍一看是要用点去覆盖边,联想到二分图的最小点权覆盖,通过拆点,我们可以得到二分图。每个点都拆成两个点,一个作为入点,另一个作为出点。于是我们构建了一个标准的二分图最小点权覆盖的模型
解决二分图最小点权覆盖的的算法并不复杂,创造一个源点和汇点,源点到左边的点连边,容量为对应点的权值,同理右边的点向汇点连边。然后运行最大流,就可以得到最小权值和。
下一步就是输出解决方案,也就是求最小割边集。在运行完最大流的残量网络中由源点出发BFS所有可以到达的点构成了源点集。对于剩下的边,如果满流且一个端点属于源点集而另一个端点不属于,则这条边属于最小割。
代码实现比较简单:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
const int maxn=110*2,maxm=5000,s=0,INF=9999999;
int n,m,t,cap[maxn][maxn],flow[maxn][maxn],w[maxn]; int augment(int fa[])
{
int d[maxn];
memset(d,0,sizeof(d));
d[s]=INF;
queue<int>q;q.push(s);
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=s;i<=t;i++)
{
if((d[i]!=0)||(cap[u][i]<=flow[u][i]))continue;
d[i]=min(d[u],cap[u][i]-flow[u][i]);
q.push(i);
fa[i]=u;
if(i==t)return d[t];
}
}
return d[t];
} int maxflow()
{
int fa[maxn];
int ans=0; while(true)
{
int nflow=augment(fa);
if(nflow==0)return ans;
ans+=nflow;
for(int i=t;i!=s;i=fa[i])
{
flow[fa[i]][i]+=nflow;
flow[i][fa[i]]-=nflow;
}
}
}
vector<int> mincut()
{
bool vis[maxn];
memset(vis,0,sizeof(vis));
vis[s]=true;
queue<int>q;
q.push(s);
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=s;i<=t;i++)
{
if((vis[i])||(cap[u][i]<=flow[u][i]))continue;
vis[i]=true;
q.push(i);
}
}
vector<int>ans;
for(int i=s;i<=t;i++)
if(vis[i])for(int j=s;j<=t;j++)
if(!vis[j]&&cap[i][j]==flow[i][j]&&cap[i][j]>0)
{
if(i==s){ans.push_back(j);}
if(j==t){ans.push_back(i);}
}
return ans;
} void print(vector<int> vec)
{
cout<<vec.size()<<endl;
for(int i=0;i<vec.size();i++)
{
if(vec[i]<=n)cout<<vec[i]<<" -"<<endl;
else cout<<vec[i]-n<<" +"<<endl;
}
}
int main()
{
ios::sync_with_stdio(false);
memset(cap,0,sizeof(cap));memset(flow,0,sizeof(flow));
cin>>n>>m;
t=n*2+1;
for(int i=1;i<=n*2;i++)
cin>>w[i];
for(int i=0;i<m;i++)
{
int a,b;
cin>>a>>b;
cap[a][b+n]=INF;
}
for(int i=1;i<=n;i++)
{
cap[s][i]=w[i+n];
cap[i+n][t]=w[i];
}
cout<<maxflow()<<endl;
print( mincut() );
return 0;
}
东北欧赛区的题目还是很给力的
POJ 2125 Destroying The Graph 二分图 最小点权覆盖的更多相关文章
- POJ 2125 Destroying the Graph 二分图最小点权覆盖
Destroying The Graph Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 8198 Accepted: 2 ...
- 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 ...
- POJ2125 Destroying The Graph 二分图 + 最小点权覆盖 + 最小割
思路来源:http://blog.csdn.net/lenleaves/article/details/7873441 求最小点权覆盖,同样求一个最小割,但是要求出割去了那些边, 只要用最终的剩余网络 ...
- POJ2125 Destroying The Graph(二分图最小点权覆盖集)
最小点权覆盖就是,对于有点权的有向图,选出权值和最少的点的集合覆盖所有的边. 解二分图最小点权覆盖集可以用最小割: vs-X-Y-vt这样连边,vs和X部点的连边容量为X部点的权值,Y部和vt连边容量 ...
- POJ - 2125 Destroying The Graph (最小点权覆盖)
题意:给一张图,现在要删去所有的边,删去一个点的所有入边和所有出边都有其对应\(W_{i+}\)和\(W_{i-}\).求删去该图的最小花费,并输出解 分析:简而言之就是用最小权值的点集去覆盖所有的边 ...
- poj 3308 Paratroopers(二分图最小点权覆盖)
Paratroopers Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 8954 Accepted: 2702 Desc ...
- POJ3308 Paratroopers(最小割/二分图最小点权覆盖)
把入侵者看作边,每一行每一列都是点,选取某一行某一列都有费用,这样问题就是选总权最小的点集覆盖所有边,就是最小点权覆盖. 此外,题目的总花费是所有费用的乘积,这时有个技巧,就是取对数,把乘法变为加法运 ...
- POJ 3308 Paratroopers(最大流最小割の最小点权覆盖)
Description It is year 2500 A.D. and there is a terrible war between the forces of the Earth and the ...
随机推荐
- 【 bzoj4537】HNOI2016 最小公倍数
首先将边按a的值分组,每$\sqrt{m}$一组. 对于每一组,将符合一组a的询问选出来,将这些询问和这一块之前的边(a一定小于这些询问)按b排序,然后交替插入,询问,对于一个询问,在当前块也有可能有 ...
- Linux开发IDE打造
一直以来都是在windows下做开发的,微软提供的IDE vs开发起来确实快捷高效,接触linux也很久了通常都是使用vim进行一些基础文件的编译,现在突然要转到linux做开发还是不太适应的,网上 ...
- jstree使用小结(三)
操作节点的这几个事件都比较简单: 如下 var $tree=$('#tree1'); $tree.jstree({...}); //选中节点 $tree.on('select_node.jstree' ...
- Session保存到指定数据库中
方法1:向数据库中添加session相关信息,可以使用官方工具 命令提示符cmd中执行: cd C:\Windows\Microsoft.NET\Framework\v4.0.30319 ...
- xamarin mac 基础知识 之 界面
有两种方式创建界面:代码和xaml
- python 数组的del ,remove,pop区别
以a=[1,2,3] 为例,似乎使用del, remove, pop一个元素2 之后 a都是为 [1,3], 如下: >>> a=[1,2,3] >>> a.rem ...
- c++初学(电梯实验加强版)
Elevator.h class Elevator{public: Elevator(); ~Elevator(); void getNowNum(); void Se ...
- Python3基础 add() 向集合中加入新的元素
镇场诗: 诚听如来语,顿舍世间名与利.愿做地藏徒,广演是经阎浮提. 愿尽吾所学,成就一良心博客.愿诸后来人,重现智慧清净体.-------------------------------------- ...
- js模块化开发——模块的写法
随着网站逐渐变成"互联网应用程序",嵌入网页的Javascript代码越来越庞大,越来越复杂. 网页越来越像桌面程序,需要一个团队分工协作.进度管理.单元测试等等......开发者 ...
- HDU-1166-敌兵布阵(线段树)
前言: 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点. 对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a, ...