poj Firing(最大重量封闭图)
Firing
题目:
要解雇一些人,而解雇的这些人假设人跟他有上下级的关系,则跟他有关系的人也要一起解雇。每一个人都会创造一定的价值,要求你求出在最大的获利下。解雇的人最小。
算法分析:
在这之前要知道一个定理:
最小割 = 最大流
一道最大权闭合图的裸题,而这又能够转换成最小割来求解。证明能够看2007年胡伯涛的论文则能够直接套出模板。没看过的最好去看一下。那里解释的清楚。
这里我给出他的原文的一些构造方法。
添加源s汇t
源s连接原图的正权点,容量为对应点权
原图的负权点连接汇t。容量为对应点权的相反数
原图边的容量为正无限.
而这里事实上最难的是第一问。而因为本人的实力有限。所以,难以解释清楚。
可是网上流传的该题解题报告的人非常少有解释清的,都是一笔带过。找了好久才找到了一篇正确的解释。以下给出解释。
////////////////////////////////////////////////////////////////
标准的最大权闭合图,构图:从源点s向每一个正收益点连边,容量为收益;从每一个负收益点向汇点t连边,容量为收益的相反数;对于i是j的上司,连边i->j,容量为inf。最大收益 = 正收益点权和 - 最小割 = 正收益点权和 - 最大流(胡波涛论文上有证明)。这题的关键是怎样在最小割的前提下求出最少的割边数目,能够从源点对残量网络进行一次DFS,每一个割都会将源汇隔开,所以从源点DFS下去一定会由于碰到某个割而无法前进,用反证法易知这时遍历过的点数就是S集的最少点数。
/////////////////////////////////////////////////////////////////
- #include <iostream>
- #include <algorithm>
- #include <vector>
- #include <queue>
- #include <cstdio>
- #include <cstring>
- using namespace std;
- typedef long long LL;
- const int MAXN = 5000 + 10;
- const LL INF = (1LL) << 60; //必须(1LL)!!!!!!!!!!!!!!!!!!!! T_T......
- struct Edge{
- int from,to;
- LL cap,flow;
- Edge(){};
- Edge(int _f,int _t,LL _c,LL _fw)
- :from(_f),to(_t),cap(_c),flow(_fw){};
- };
- vector<Edge> edges;
- vector<int> G[MAXN];
- bool vst[MAXN];
- int d[MAXN],cur[MAXN];
- int V,E,S,T;
- int cnt; //最少割边数
- LL ans,sum;
- void clr(){
- ans = sum = 0;
- S = 0; T = V + 1;
- for(int i = 0;i <= V;++i)
- G[i].clear();
- edges.clear();
- }
- void addEdge(int f,int t,LL cap){
- edges.push_back(Edge(f,t,cap,0));
- edges.push_back(Edge(t,f,0,0));
- int sz = edges.size();
- G[f].push_back(sz - 2);
- G[t].push_back(sz - 1);
- }
- void init(){
- LL x;
- for(int i = 1;i <= V;++i){
- scanf("%I64d",&x);
- if(x > 0){
- addEdge(S,i,x);
- sum += x;
- } else {
- addEdge(i,T,-x);
- }
- }
- int a,b;
- for(int i = 0;i < E;++i){
- scanf("%d%d",&a,&b);
- addEdge(a,b,INF);
- }
- }
- bool BFS(){
- memset(vst,0,sizeof(vst));
- queue<int> Q;
- Q.push(S);
- d[S] = 0;
- vst[S] = 1;
- while(!Q.empty()){
- int x = Q.front(); Q.pop();
- for(int i = 0;i < (int)G[x].size();++i){
- Edge& e = edges[G[x][i]];
- if(!vst[e.to] && e.cap > e.flow){
- vst[e.to] = 1;
- d[e.to] = d[x] + 1;
- Q.push(e.to);
- }
- }
- }
- return vst[T];
- }
- LL DFS(int x,LL a){
- if(x == T||a == 0)
- return a;
- LL flow = 0,f;
- for(int& i = cur[x];i < (int)G[x].size();++i){
- Edge& e = edges[G[x][i]];
- if(d[x] + 1 == d[e.to]&&(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;
- }
- LL Maxflow(){
- LL flow = 0;
- while(BFS()){
- memset(cur,0,sizeof(cur));
- flow += DFS(S,INF);
- }
- return flow;
- }
- //求解在最小割的前提下,得最好割边
- void dfs(int u){
- vst[u] = 1;
- for(int i = 0;i < (int)G[u].size();++i){
- Edge& e = edges[G[u][i]];
- if(!vst[e.to] && e.cap > e.flow){
- cnt++;
- dfs(e.to);
- }
- }
- }
- void solve(){
- LL ans = sum - Maxflow();
- cnt = 0;
- memset(vst,0,sizeof(vst));
- dfs(S);
- printf("%d %I64d\n",cnt,ans);
- }
- int main()
- {
- // freopen("Input.txt","r",stdin);
- while(~scanf("%d%d",&V,&E)){
- clr();
- init();
- solve();
- }
- return 0;
- }
poj Firing(最大重量封闭图)的更多相关文章
- POJ 1724 (分层图最短路)
### POJ 1724 题目链接 ### 题目大意: 给你 N 个点 ,M 条有向路,走每条路需要花费 C 元,这段路的长度为 L . 给你 K 元,问你能否从 1 走到 N 点且花费不超过 K 元 ...
- POJ 1625 Censored ( Trie图 && DP && 高精度 )
题意 : 给出 n 个单词组成的字符集 以及 p 个非法串,问你用字符集里面的单词构造长度为 m 的单词的方案数有多少种? 分析 :先构造出 Trie 图方便进行状态转移,这与在 POJ 2278 中 ...
- poj 3648 2-SAT建图+topsort输出结果
其实2-SAT类型题目的类型比较明确,基本模型差不多是对于n组对称的点,通过给出的限制条件建图连边,然后通过缩点和判断冲突来解决问题.要注意的是在topsort输出结果的时候,缩点后建图需要反向连边, ...
- poj 3683 2-sat建图+拓扑排序输出结果
发现建图的方法各有不同,前面一题连边和这一题连边建图的点就不同,感觉这题的建图方案更好. 题意:给出每个婚礼的2个主持时间,每个婚礼的可能能会冲突,输出方案. 思路:n个婚礼,2*n个点,每组点是对称 ...
- POJ 3310 Caterpillar(图的度的判定)
题意: 给定一幅图, 问符不符合一下两个条件: (1) 图中没有环 (2)图中存在一条链, 点要么在链上, 要么是链上点的邻居. 分析: 建图,记录度数, 去掉所有度为1的点, 然后看看剩下是否是有2 ...
- POJ 1149 PIGS 建图,最大流
题意: 你m个猪圈以及每个猪圈里原来有多少头猪,先后给你n个人,每个人能打开某一些猪圈并且他们最多想买Ki头猪,在每一个人买完后能将打开的猪圈中的猪顺意分配在这次打开猪圈里,在下一个人来之前 已打开的 ...
- poj 3635 Full Tank? ( 图上dp )
题意: 已知每一个点的加油站的油价单位价格(即点权).每条路的长度(边权). 有q个询问.每一个询问包含起点s.终点e和油箱容量. 问从起点走到终点的最小花费.假设不可达输出impossible,否则 ...
- Friendship POJ - 1815 基本建图
In modern society, each person has his own friends. Since all the people are very busy, they communi ...
- hdu 3917 最大重量封闭图
/*最大重量封闭图: 意甲冠军:一些城市要建路需要负责一些公司,每家公司都需要缴纳个税.该公司将需要花费每路,另一个限制条件,如果那家公司a既定a-b.公司b既定b-c然后选择 公司a 你必须选择一个 ...
随机推荐
- android编译自己 内置的jar做法
1.首先 android.mk LOCAL_PATH := $(call my-dir) # ===================================================== ...
- Exception in thread "http-apr-8080-exec-6" java.lang.OutOfMemoryError: PermGen space 解决!
Exception in thread "http-apr-8080-exec-6" java.lang.OutOfMemoryError: PermGen space at ja ...
- MySql 安装及0基础使用具体解释
1. sudo apt-get install mysql-server, input administrator password , '123' 2. enter mysql promot in ...
- 【网络协议】TCP交互数据流和数据流成块
前言 建立在TCP协议上的应用层协议有非常多,如FTP.HTTP.Telnet等,这些协议依据数据传输的多少能够分为两类:交互数据类型和成块数据类型. 交互数据类型,如:Telnet,这类协议一般仅仅 ...
- Python 收集Twitter时间序列数据
CODE: #!/usr/bin/python # -*- coding: utf-8 -*- ''' Created on 2014-7-18 @author: guaguastd @name: c ...
- android系统reboot
这里所说的reboot指的是软件重启,并非断电重启.我们知道android系统的几个功能,比如:回复出厂设置.OTA升级等都需要重启系统,而且重启后要进入recovery模式,有的手机还带有重启进入f ...
- .Net程序猿玩转Android开发---(7)相对布局RelativeLayout
相对布局RelativeLayout是Android布局中一个比較经常使用的控件,使用该控件能够布局出适合各种屏幕分辨率的布局,RelativeLayout採用相对位置进行 ...
- poj1260
给定n类等级的珍珠 每类的珍珠都有需求的个数ai,和价格pi 为了防止游客只买1颗珍珠,所以购买ai个珍珠时,要加上10个的价格 即(ai+10)*pi 有时,购买高等级的珍珠代替低等级的珍珠时,可能 ...
- windows phone 独立存储空间的操作 (2)
原文:windows phone 独立存储空间的操作 (2) IsolatedStorage独立存储空间是保存应用程序的一些数据已经配置文件,独立存储空间相对于其他的wp程序是独立的,也就是说每个wp ...
- ASP.NET——验证码的制作
我们在登陆站点,发表博客或者提交评论的时候,常常会遇到填写验证码这一项,当时感觉挺奇妙的样子,最终在牛腩新闻公布系统里接触到了,在这里小小的总结下. 用到的东东有三个: ...