描述

周末,小Hi和小Ho所在的班级决定举行一些班级建设活动。

根据周内的调查结果,小Hi和小Ho一共列出了N项不同的活动(编号1..N),第i项活动能够产生a[i]的活跃值。

班级一共有M名学生(编号1..M),邀请编号为i的同学来参加班级建设活动需要消耗b[i]的活跃值。

每项活动都需要某些学生在场才能够进行,若其中有任意一个学生没有被邀请,这项活动就没有办法进行。

班级建设的活跃值是活动产生的总活跃值减去邀请学生所花费的活跃值。

小Hi和小Ho需要选择进行哪些活动,来保证班级建设的活跃值尽可能大。

比如有3项活动,4名学生:

第1项活动产生5的活跃值,需要编号为1、2的学生才能进行;

第2项活动产生10的活跃值,需要编号为3、4的学生才能进行;

第3项活动产生8的活跃值,需要编号为2、3、4的学生才能进行。

编号为1到4的学生需要消耗的活跃值分别为6、3、5、4。

假设举办活动集合为{1},需要邀请的学生集合为{1,2},则得到的班级活跃值为5-9 = -4。

假设举办活动集合为{2},需要邀请的学生集合为{3,4},则得到的班级活跃值为10-9 = 1。

假设举办活动集合为{2,3},需要邀请的学生集合为{2,3,4},则得到的班级活跃值为18-12 = 6。

假设举办活动集合为{1,2,3},需要邀请的学生集合为{1,2,3,4},则得到的班级活跃值为23-18 = 5。

小Hi和小Ho总是希望班级活跃值越大越好,因此在这个例子中,他们会选择举行活动2和活动3。

提示:最大权闭合子图

小Ho:这次的问题好像还是很麻烦的样子啊。

小Hi:没错,小Ho你有什么想法么?

小Ho:我么?我能想到只有枚举啦。因为每一项活动都只有举行和不举行两种状态,因此我直接用O(2^N)的枚举,再对选出来的情况进行计算。最后选出最大的方案。

小Hi:这很明显会超过时间限制吧。

小Ho:我知道啊,那有什么好的方法么?

小Hi:当然有啊,这次我们需要解决的是闭合子图问题。

小Ho:这个闭合子图是啥?

小Hi:所谓闭合子图就是给定一个有向图,从中选择一些点组成一个点集V。对于V中任意一个点,其后续节点都仍然在V中。比如:

在这个图中有8个闭合子图:∅,{3},{4},{2,4},{3,4},{1,3,4},{2,3,4},{1,2,3,4}

小Ho:闭合子图我懂了,但是这跟我们这次的问题有啥关系呢?

小Hi:我们先把这次的问题转化为2分图。将N个活动看作A部,将M个学生看作B部。若第i个活动需要第j个学生,就连一条从A[i]到B[j]的有向边。比如对于例子:

假如选择A[1],则我们需要同时选择B[1],B[2]。那么选择什么活动和其需要的学生,是不是就刚好对应了这个图中的一个闭合子图呢?

小Ho:你这么一说好像还真是。如果把活跃值算作权值,A部的节点包含有正的权值,B部的节点是负的权值。那么我们要求的也就是一个权值最大的闭合子图了?

小Hi:没错,我们要求解的正是最大权闭合子图。它的求解方法是使用网络流,因此我们需要将这个图再进一步转化为网络流图。

对于一般的图来说:首先建立源点s和汇点t,将源点s与所有权值为正的点相连,容量为权值;将所有权值为负的点与汇点t相连,容量为权值的绝对值;权值为0的点不做处理;同时将原来的边容量设置为无穷大。举个例子:

对于我们题目中的例子来说,其转化的网络流图为:

上图中黑边表示容量无穷大的边。

小Ho:转化模型这一步看上去不是太难,然后呢?

小Hi:先说说结论吧,最大权闭合子图的权值等于所有正权点之和减去最小割。

接下来来证明这个结论,首先我们要证明两个引理:

1. 最小割一定是简单割

简单割指得是:割(S,T)中每一条割边都与s或者t关联,这样的割叫做简单割。

因为在图中将所有与s相连的点放入割集就可以得到一个割,且这个割不为正无穷。而最小割一定小于等于这个割,所以最小割一定不包含无穷大的边。因此最小割一定一个简单割。

2. 简单割一定和一个闭合子图对应

闭合子图V和源点s构成S集,其余点和汇点t构成T集。

首先证明闭合子图是简单割:若闭合子图对应的割(S,T)不是简单割,则存在一条边(u,v),u∈S,v∈T,且c(u,v)=∞。说明u的后续节点v不在S中,产生矛盾。

接着证明简单割是闭合子图:对于V中任意一个点u,u∈S。u的任意一条出边c(u,v)=∞,不会在简单割的割边集中,因此v不属于T,v∈S。所以V的所有点均在S中,因此S-s是闭合子图。

由上面两个引理可以知道,最小割也对应了一个闭合子图,接下来证明最小割就是最大权的闭合子图。

首先有割的容量C(S,T)=T中所有正权点的权值之和+S中所有负权点的权值绝对值之和。

闭合子图的权值W=S中所有正权点的权值之和-S中所有负权点的权值绝对值之和。

则有C(S,T)+W=T中所有正权点的权值之和+S中所有正权点的权值之和=所有正权点的权值之和。

所以W=所有正权点的权值之和-C(S,T)

由于所有正权点的权值之和是一个定值,那么割的容量越小,W也就越大。因此当C(S,T)取最小割时,W也就达到了最大权。

小Ho:我懂了,因为最小割也对应了一个闭合子图,因此它是可以被取得的,W也才能够到达最大权值。

小Hi:没错,这就是前面两条引理的作用。

小Ho:那么最小割的求解就还是用最大流来完成好了!

小Hi:嗯,那就交给你了。

 
#include <bits/stdc++.h>
using namespace std; #define maxn 505
#define INF 0x3f3f3f3f struct Edge
{
int from,to,cap,flow;
}; struct Dinic
{
int n,m,s,t;
vector<Edge> edge;
vector<int> G[maxn];
bool vis[maxn];
int d[maxn];
int cur[maxn]; void init()
{
for(int i=;i<maxn;i++)
G[i].clear();
edge.clear();
memset(d,,sizeof(d));
memset(vis,,sizeof(vis));
memset(cur,,sizeof(cur));
} void addEdge (int from,int to,int cap)
{
edge.push_back((Edge){from,to,cap,});
edge.push_back((Edge){to,from,,});
m = edge.size();
G[from].push_back(m-);
G[to].push_back(m-);
} bool BFS()
{
memset(vis,,sizeof(vis));
queue<int> Q;
Q.push(s);
d[s] = ;
vis[s] = ;
while(!Q.empty())
{
int x = Q.front();
Q.pop();
for(int i=; i<G[x].size(); i++)
{
Edge & e = edge[G[x][i]];
if(!vis[e.to]&&e.cap>e.flow)
{
vis[e.to] = ;
d[e.to] = d[x] + ;
Q.push(e.to);
}
}
}
return vis[t];
} long long DFS(int x,int a)
{
if(x==t||a==) return a;
long long flow = ,f;
for(int & i = cur[x]; i<G[x].size(); i++)
{
Edge & e = edge[G[x][i]];
if(d[x] + ==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>)
{
e.flow +=f;
edge[G[x][i]^].flow -=f;
flow +=f;
a-=f;
if(a==) break;
}
}
return flow;
} int Maxflow (int s,int t) {
this->s = s;this->t = t;
int flow = ;
while(BFS()) {
memset(cur,,sizeof(cur));
flow+=DFS(s,INF);
}
return flow;
} //求最小割S,T;
void new_BFS(int s,int n)
{
memset(vis,,sizeof(vis));
d[s] = ;
vis[s] = ;
queue<int> Q;
Q.push(s);
while(!Q.empty())
{
int u = Q.front();
Q.pop(); for(int i=;i<G[u].size();i++)
{
Edge & e = edge[G[u][i]];
if(!vis[e.to]&&e.cap>e.flow)
{
vis[e.to] = ;
d[e.to] = d[u] + ;
Q.push(e.to);
}
}
} int cnt = ;
for(int i=;i<=n;i++)
{
if(vis[i]) cnt++;
}
printf("%d\n",cnt);
for(int i=;i<=n;i++)
if(vis[i]) printf("%d ",i);
puts("");
} }sol; int main()
{
sol.init();
int n;
int m;
scanf("%d%d",&n,&m);
int s=;
int t=n+m+;
int cap;
for(int i=; i<=m; i++)
{
scanf("%d",&cap);
sol.addEdge(n+i,t,cap);
} int sum = ;
for(int i=; i<=n; i++)
{
int a,k;
scanf("%d%d",&a,&k);
sum+=a;
sol.addEdge(s,i,a);
for(int j=; j<k; j++)
{
int v;
scanf("%d",&v);
sol.addEdge(i,v+n,INF);
}
}
printf("%d\n",sum-sol.Maxflow(s,t)); return ;
}

闭合子图: 就是按图1说的,1加到集合里面去了,那么与之相连的3,4必须到集合中去,那么一张图就有很多个闭合子图。

然后每个点都有一个权值,要求一个权值最大的子图。

结论:最大权闭合子图 = 正点和-最小割。

分析:

1,一个最小割肯定是一个子图。证明上面有,但是我没看懂。

2,有了上一点:

割的容量C(S,T) = S中的正权点之和+ T中负权点绝对值之和。

闭合子图的权值W = S中的正权点之和 - S中负权点绝对值之和。

可以推出 W = 所有正权点之和 - C(S,T);

还是看图说话吧:

最大流 = 最小割 = 17,正点之和 = 23,最大权闭合子图 = 23-17 = 6;

 

hiho 第119周 最大权闭合子图的更多相关文章

  1. hiho# 1398 最大权闭合子图 网络流

    题目传送门 题意:给出n个活动,m个人,请人需要花费$a[i]$的钱,举办一次活动可以赚$b[i]$的钱,但是需要固定的几个人在场,一个人只需要请一次后就必定在场,问最大收益. 思路: 下列结论来自h ...

  2. HihoCoder 1398 网络流 - 最大权闭合子图

    周末,小Hi和小Ho所在的班级决定举行一些班级建设活动. 根据周内的调查结果,小Hi和小Ho一共列出了N项不同的活动(编号1..N),第i项活动能够产生a[i]的活跃值. 班级一共有M名学生(编号1. ...

  3. BZOJ1565 [NOI2009]植物大战僵尸(拓扑排序 + 最大权闭合子图)

    题目 Source http://www.lydsy.com/JudgeOnline/problem.php?id=1565 Description Input Output 仅包含一个整数,表示可以 ...

  4. HDU 3879 Base Station(最大权闭合子图)

    经典例题,好像说可以转化成maxflow(n,n+m),暂时只可以勉强理解maxflow(n+m,n+m)的做法. 题意:输入n个点,m条边的无向图.点权为负,边权为正,点权为代价,边权为获益,输出最 ...

  5. [BZOJ 1497][NOI 2006]最大获利(最大权闭合子图)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1497 分析: 这是在有向图中的问题,且边依赖于点,有向图中存在点.边之间的依赖关系可以 ...

  6. HDU4971 A simple brute force problem.(强连通分量缩点 + 最大权闭合子图)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=4971 Description There's a company with several ...

  7. HDU5855 Less Time, More profit(最大权闭合子图)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5855 Description The city planners plan to build ...

  8. HDU5772 String problem(最大权闭合子图)

    题目..说了很多东西 官方题解是这么说的: 首先将点分为3类 第一类:Pij 表示第i个点和第j个点组合的点,那么Pij的权值等于w[i][j]+w[j][i](表示得分) 第二类:原串中的n个点每个 ...

  9. SCU3109 Space flight(最大权闭合子图)

    嗯,裸的最大权闭合子图. #include<cstdio> #include<cstring> #include<queue> #include<algori ...

随机推荐

  1. [原创] 分享一些linux教程

    书<鸟哥的linux私房菜第三版>,链接:http://pan.baidu.com/s/1i3femnr 配套视频,链接:http://pan.baidu.com/s/1v72xw --- ...

  2. sqlserver 存储过程 以及统计整个数据库数据

    drop proc test 删除存储过程 go  用于在 SSMS 和 SQLCMD 中将其之前的 T-SQL 语句作为一个批处理提交给 SQL Server 实例.GO 不是 T-SQL 语句,只 ...

  3. web server与app server有什么不同

    简单来说,web服务器提供页面给浏览器,而app服务器提供客户端可以调用的接口.具体而言,我们可以说: Web服务器处理HTTP请求,而app服务器基于多种不同的协议,处理应用程序的逻辑问题. 以下将 ...

  4. CCF真题之Z字形扫描

    201412-2 问题描述 在图像编码的算法中,需要将一个给定的方形矩阵进行Z字形扫描(Zigzag Scan).给定一个n×n的矩阵,Z字形扫描的过程如下图所示: 对于下面的4×4的矩阵, 1 5 ...

  5. $.getJSON异步请求和同步请求

    先说一下我遇到的问题吧,我之前的一个函数想调用上一个函数的返回值,但是它的返回值一直为空,后来翻了一些资料才明白是异步请求在作怪,不多说,看例子,这是我之前有返回值函数的代码: function ge ...

  6. Kafka集群模式部署

    环境:kafka 0.8.1.1 基本概念 Kafka维护按类区分的消息,称为主题(topic) 生产者(producer)向kafka的主题发布消息 消费者(consumer)向主题注册,并且接收发 ...

  7. (转)oracle 查看表所占用的空间大小

    1.查看表所占空间 SELECT   TABLESPACE_NAME,TO_CHAR(SUM(BYTES)/(1024*1024),'999G999D999')   CNT_MB     FROM   ...

  8. 夺命雷公狗---微信开发58----微网站之jquery_mobile之控件介绍

    我们上一节课里面介绍了基本的jqm是如何用的了,那么这一节课我们就开始玩玩他的控件 1...布局网格 <!DOCTYPE html> <html> <head> & ...

  9. pic计数

    #include <pic.h> //用的是PICC编译器 __CONFIG (HS & PROTECT & PWRTEN & BOREN & WDTDIS ...

  10. Python for z/OS

    Install pythondev Install DB2 or server driver package easy_install ibm_db Get license file from tor ...