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(最大重量封闭图)的更多相关文章

  1. POJ 1724 (分层图最短路)

    ### POJ 1724 题目链接 ### 题目大意: 给你 N 个点 ,M 条有向路,走每条路需要花费 C 元,这段路的长度为 L . 给你 K 元,问你能否从 1 走到 N 点且花费不超过 K 元 ...

  2. POJ 1625 Censored ( Trie图 && DP && 高精度 )

    题意 : 给出 n 个单词组成的字符集 以及 p 个非法串,问你用字符集里面的单词构造长度为 m 的单词的方案数有多少种? 分析 :先构造出 Trie 图方便进行状态转移,这与在 POJ 2278 中 ...

  3. poj 3648 2-SAT建图+topsort输出结果

    其实2-SAT类型题目的类型比较明确,基本模型差不多是对于n组对称的点,通过给出的限制条件建图连边,然后通过缩点和判断冲突来解决问题.要注意的是在topsort输出结果的时候,缩点后建图需要反向连边, ...

  4. poj 3683 2-sat建图+拓扑排序输出结果

    发现建图的方法各有不同,前面一题连边和这一题连边建图的点就不同,感觉这题的建图方案更好. 题意:给出每个婚礼的2个主持时间,每个婚礼的可能能会冲突,输出方案. 思路:n个婚礼,2*n个点,每组点是对称 ...

  5. POJ 3310 Caterpillar(图的度的判定)

    题意: 给定一幅图, 问符不符合一下两个条件: (1) 图中没有环 (2)图中存在一条链, 点要么在链上, 要么是链上点的邻居. 分析: 建图,记录度数, 去掉所有度为1的点, 然后看看剩下是否是有2 ...

  6. POJ 1149 PIGS 建图,最大流

    题意: 你m个猪圈以及每个猪圈里原来有多少头猪,先后给你n个人,每个人能打开某一些猪圈并且他们最多想买Ki头猪,在每一个人买完后能将打开的猪圈中的猪顺意分配在这次打开猪圈里,在下一个人来之前 已打开的 ...

  7. poj 3635 Full Tank? ( 图上dp )

    题意: 已知每一个点的加油站的油价单位价格(即点权).每条路的长度(边权). 有q个询问.每一个询问包含起点s.终点e和油箱容量. 问从起点走到终点的最小花费.假设不可达输出impossible,否则 ...

  8. Friendship POJ - 1815 基本建图

    In modern society, each person has his own friends. Since all the people are very busy, they communi ...

  9. hdu 3917 最大重量封闭图

    /*最大重量封闭图: 意甲冠军:一些城市要建路需要负责一些公司,每家公司都需要缴纳个税.该公司将需要花费每路,另一个限制条件,如果那家公司a既定a-b.公司b既定b-c然后选择 公司a 你必须选择一个 ...

随机推荐

  1. CMake Intro - CMakeLists.txt

    Notes:  directory structure:  cmake, cmake/Tutorial, cmake/Tutorial/MathLibs 1. File lists in cmake/ ...

  2. python语言学习7——数据类型和变量

    整数 python可以处理任意大小的整数,包括负整数,在程序中的表示方法和数学上的写法一样 计算机由于使用二进制,有时候采用十六进制表示整数比较方便,十六进制数用0x前缀 浮点数 简单的小数就直接用小 ...

  3. Ubuntu Manpage: ajaxterm - Web based terminal written in python

    Ubuntu Manpage: ajaxterm - Web based terminal written in python hardy (1) ajaxterm.1.gz Provided by: ...

  4. android各种资源的详细解释

    1.字符数组      使用字符串数组资源<string-array>标签定义,在<string-array>包括一些标签<item>数组元素标记.   例如 &l ...

  5. WPF中不规则窗体与WebBrowser控件的兼容问题解决办法

    原文:WPF中不规则窗体与WebBrowser控件的兼容问题解决办法 引言 这几天受委托开发一个网络电视项目,要求初步先使用内嵌网页形式实现视频播放和选单,以后再考虑将网页中的所有功能整合进桌面程序. ...

  6. socket用法

    INADDR_ANY是ANY,是绑定地址0.0.0.0上的监听, 能收到任意一块网卡的连接:INADDR_LOOPBACK, 也就是绑定地址LOOPBAC, 往往是127.0.0.1, 只能收到127 ...

  7. 采用keepalived施工可用性MySQL-HA

    描述了使用keepalived施工可用性MySQL-HA,两个保证MySQL数据一致性,然后,keepalived虚拟IP,经keepalived内置的在线监测功能来实现MySQL. AD: 关于My ...

  8. 同时显示多个 Notification

    主要出在PendingIntent.getActivity();的第二个参数,API文档里虽然说是未被使用的参数(给出的例子也直接写0的),实际上是通过该参数来区别不同的Intent的,如果id相同, ...

  9. 用JavaScript实现网页动态水印

    1.基本原理 页面加载后,通过javascript创建页面元素div,并在div元素中创建文本节点,展示水印内容 设置div元素样式,将其zIndex设置一个较高的值,并设置透明度,实现浮在页面的水印 ...

  10. net MVC 的八个扩展点

    net MVC 的八个扩展点 MVC模型以低耦合.可重用.可维护性高等众多优点已逐渐代替了WebForm模型.能够灵活使用MVC提供的扩展点可以达到事半功倍的效果,另一方面Asp.net MVC优秀的 ...