洛谷 P4174 [NOI2006]最大获利 && 洛谷 P2762 太空飞行计划问题 (最大权闭合子图 && 最小割输出任意一组方案)
https://www.luogu.org/problemnew/show/P4174
最大权闭合子图的模板
每个通讯站建一个点,点权为-Pi;每个用户建一个点,点权为Ci,分别向Ai和Bi对应的点连边;然后就可以跑了
方法是:
建新源S和新汇T,从S向所有正权点连边,容量为点权值;从所有负权点向T连边,容量为点权值的相反数;原图中所有边容量设为无穷大
跑S到T最大流
原因:(网上都有,自己研究的也不知道有没有偏差)
找出图的任意一个割,其中:
显然不可能割掉容量为无穷大的边;
割掉一条S到u的边,表示不取点u,同时舍弃u点的价值;
割掉一条v到T的边,表示取点v,同时加上v点的代价;
能保证割完这个割中的边后,S到T不连通,即保证不存在任意路径,从S到u经过一些点到v再到T,即保证不存在一个u点需要被取,但是它能到达的一个节点v没有被取。
因此,一个割对应一种闭合子图方案
同样的,可以证明一种闭合子图方案一定对应这样的一个割。
那么,求出最小割,就求出了最小的"舍弃的价值和"+"加上的代价和",设其为x,则最大权闭合子图的点权和等于所有正点权和-x,而最小割等于最大流
- #include<cstdio>
- #include<algorithm>
- #include<cstring>
- #include<vector>
- #include<queue>
- using namespace std;
- #define fi first
- #define se second
- #define mp make_pair
- #define pb push_back
- typedef long long ll;
- typedef unsigned long long ull;
- typedef pair<int,int> pii;
- namespace F
- {
- struct E
- {
- int to,nxt,from,cap,flow;
- }e[];
- int f1[],ne=;
- int S,T,n;
- int d[];
- bool bfs()
- {
- int k,u;
- memset(d,,sizeof(int)*(n+));
- queue<int> q;
- q.push(S);d[S]=;
- while(!q.empty())
- {
- u=q.front();q.pop();
- for(k=f1[u];k;k=e[k].nxt)
- if(!d[e[k].to]&&e[k].cap>e[k].flow)
- {
- d[e[k].to]=d[u]+;
- //if(e[k].to==T) return 1;
- q.push(e[k].to);
- }
- }
- //return 0;
- return d[T];
- }
- int cur[];
- int dfs(int u,int x)
- {
- if(u==T||x==) return x;
- int flow=,f;
- for(int &k=cur[u];k;k=e[k].nxt)
- if(e[k].cap>e[k].flow&&d[e[k].to]==d[u]+)
- {
- f=dfs(e[k].to,min(x-flow,e[k].cap-e[k].flow));
- e[k].flow+=f;e[k^].flow-=f;flow+=f;
- if(flow==x) return flow;
- }
- return flow;
- }
- int solve()
- {
- int flow=;
- while(bfs())
- {
- memcpy(cur,f1,sizeof(int)*(n+));
- flow+=dfs(S,0x3f3f3f3f);
- }
- return flow;
- }
- void me(int a,int b,int c)
- {
- e[++ne].to=b;e[ne].nxt=f1[a];f1[a]=ne;
- e[ne].from=a;e[ne].cap=c;
- e[++ne].to=a;e[ne].nxt=f1[b];f1[b]=ne;
- e[ne].from=b;e[ne].cap=;
- }
- }
- int n,m;
- int main()
- {
- int i,a,b,c,ss=,t;
- scanf("%d%d",&n,&m);F::n=n+m+;F::S=n+m+;F::T=n+m+;
- for(i=;i<=n;i++)
- {
- scanf("%d",&t);
- F::me(i,F::T,t);
- //ss-=t;
- }
- for(i=;i<=m;i++)
- {
- scanf("%d%d%d",&a,&b,&c);
- F::me(F::S,i+n,c);
- F::me(i+n,a,0x3f3f3f3f);
- F::me(i+n,b,0x3f3f3f3f);
- ss+=c;
- }
- printf("%d",ss-F::solve());
- return ;
- }
upd20190307:
貌似cf出了重题,但是要改longlonghttps://codeforces.com/problemset/problem/1082/G
https://www.luogu.org/problemnew/show/P2762
这题也是一样,但是要输出方案
按照上面的方法,只要找出任意一组最小割就容易找到输出方法了
怎么找最小割?只要找出跑出最大流以后,找出残量网络中源点S能到达的点集s1,取t1=所有点的集合-s1,那么割掉原图中所有s1,t1间的边即可
这里面有一个看起来比较靠谱的证明:https://hihocoder.com/problemset/problem/1378
- #include<cstdio>
- #include<algorithm>
- #include<cstring>
- #include<vector>
- #include<queue>
- #include<iostream>
- using namespace std;
- #define fi first
- #define se second
- #define mp make_pair
- #define pb push_back
- typedef long long ll;
- typedef unsigned long long ull;
- typedef pair<int,int> pii;
- namespace F
- {
- struct E
- {
- int to,nxt,from,cap,flow;
- }e[];
- int f1[],ne=;
- int S,T,n;
- int d[];
- bool bfs()
- {
- int k,u;
- memset(d,,sizeof(int)*(n+));
- queue<int> q;
- q.push(S);d[S]=;
- while(!q.empty())
- {
- u=q.front();q.pop();
- for(k=f1[u];k;k=e[k].nxt)
- if(!d[e[k].to]&&e[k].cap>e[k].flow)
- {
- d[e[k].to]=d[u]+;
- //if(e[k].to==T) return 1;
- q.push(e[k].to);
- }
- }
- //return 0;
- return d[T];
- }
- int cur[];
- int dfs(int u,int x)
- {
- if(u==T||x==) return x;
- int flow=,f;
- for(int &k=cur[u];k;k=e[k].nxt)
- if(e[k].cap>e[k].flow&&d[e[k].to]==d[u]+)
- {
- f=dfs(e[k].to,min(x-flow,e[k].cap-e[k].flow));
- e[k].flow+=f;e[k^].flow-=f;flow+=f;
- if(flow==x) return flow;
- }
- return flow;
- }
- int solve()
- {
- int flow=;
- while(bfs())
- {
- memcpy(cur,f1,sizeof(int)*(n+));
- flow+=dfs(S,0x3f3f3f3f);
- }
- return flow;
- }
- void me(int a,int b,int c)
- {
- e[++ne].to=b;e[ne].nxt=f1[a];f1[a]=ne;
- e[ne].from=a;e[ne].cap=c;
- e[++ne].to=a;e[ne].nxt=f1[b];f1[b]=ne;
- e[ne].from=b;e[ne].cap=;
- }
- }
- int n,m;
- char tools[];
- bool ok[];
- int tt[];
- void work()
- {
- int k,u;
- memset(ok,,sizeof(bool)*(n+));
- queue<int> q;
- q.push(F::S);ok[F::S]=;
- using F::f1;using F::e;
- while(!q.empty())
- {
- u=q.front();q.pop();
- for(k=f1[u];k;k=e[k].nxt)
- if(!ok[e[k].to]&&e[k].cap>e[k].flow)
- {
- q.push(e[k].to);
- ok[e[k].to]=;
- }
- }
- for(int i=;i<=F::n;i++)
- if(ok[i])
- {
- for(k=f1[i];k;k=e[k].nxt)
- if(k%==&&!ok[e[k].to])
- tt[++tt[]]=k;
- }
- }
- bool nok[];
- int main()
- {
- int i,a,b,c,ss=,t;
- scanf("%d%d",&m,&n);F::n=n+m+;F::S=n+m+;F::T=n+m+;
- for(i=;i<=m;i++)
- {
- scanf("%d",&t);
- F::me(F::S,i,t);
- ss+=t;
- cin.getline(tools,);
- int ulen=,tool;
- while(sscanf(tools+ulen,"%d",&tool)==)
- {
- F::me(i,tool+m,0x3f3f3f3f);
- if(tool==)
- ulen++;
- else
- {
- while(tool)
- {
- tool/=;
- ulen++;
- }
- }
- ulen++;
- }
- }
- for(i=;i<=n;i++)
- {
- scanf("%d",&t);
- F::me(i+m,F::T,t);
- }
- int an=ss-F::solve();
- work();
- for(i=;i<=tt[];i++)
- {
- using F::e;
- if(e[tt[i]].from==F::S)
- {
- nok[e[tt[i]].to]=;
- }
- }
- for(i=;i<=m;i++)
- if(!nok[i])
- printf("%d ",i);
- puts("");
- for(i=;i<=tt[];i++)
- {
- using F::e;
- if(e[tt[i]].to==F::T)
- {
- printf("%d ",e[tt[i]].from-m);
- }
- }
- puts("");
- printf("%d",an);
- return ;
- }
洛谷 P4174 [NOI2006]最大获利 && 洛谷 P2762 太空飞行计划问题 (最大权闭合子图 && 最小割输出任意一组方案)的更多相关文章
- 洛谷P2762 太空飞行计划问题(最大权闭合图)
题意 有$m$个实验,$n$中器材,每个实验需要使用一些器材 每个实验有收入,每个器材有花费 最大化收入 - 花费 Sol 最大权闭合图的经典应用 从$S$向每个实验连流量为该实验收入的边 从每个器材 ...
- 【最大权闭合子图 最小割】bzoj1497: [NOI2006]最大获利
最大权闭合子图的模型:今天才发现dinic板子是一直挂的…… Description 新的技术正冲击着手机通讯市场,对于各大运营商来说,这既是机遇,更是挑战.THU集团旗下的CS&T通讯公司在 ...
- 洛谷 P2762 太空飞行计划问题 【最大权闭合子图+最小割】
--一道难在读入的题. 最后解决方案直接getline一行然后是把读优拆掉放进函数,虽然很丑但是过了. 然后就是裸的最大权闭合子图了,把仪器当成负权点向t连流量为其价格的边,s向实验连流量为实验报酬的 ...
- bzoj 1497 [NOI2006]最大获利【最大权闭合子图+最小割】
不要被5s时限和50000点数吓倒!大胆网络流!我一个5w级别的dinic只跑了1s+! 看起来没有最大权闭合子图的特征--限制,实际上还是有的. 我们需要把中转站看成负权点,把p看成点权,把客户看成 ...
- 洛谷 P2762 太空飞行计划问题 P3410 拍照【最大权闭合子图】题解+代码
洛谷 P2762 太空飞行计划问题 P3410 拍照[最大权闭合子图]题解+代码 最大权闭合子图 定义: 如果对于一个点集合,其中任何一个点都不能到达此集合以外的点,这就叫做闭合子图.每个点都有一个权 ...
- 洛谷 P4174 [NOI2006]最大获利 解题报告
P4174 [NOI2006]最大获利 题目描述 新的技术正冲击着手机通讯市场,对于各大运营商来说,这既是机遇,更是挑战.THU 集团旗下的 CS&T 通讯公司在新一代通讯技术血战的前夜,需要 ...
- 洛谷P4174 [NOI2006]最大获利(最大流)
题目描述 新的技术正冲击着手机通讯市场,对于各大运营商来说,这既是机遇,更是挑战.THU 集团旗下的 CS&T 通讯公司在新一代通讯技术血战的前夜,需要做太多的准备工作,仅就站址选择一项,就需 ...
- [洛谷P4174][NOI2006]最大获利
题目大意:同Petya and Graph,数据范围改成$n\leqslant5\times10^3,m\leqslant5\times10^4$ 题解:同上 卡点:无 C++ Code: #incl ...
- 洛谷 [P2762] 太空飞行计划问题
最大权闭合子图 胡伯涛论文真是个好东西.jpg 求一个有向图的最大权闭合子图,常应用于有先决条件的最优化问题中 将所有正权点与源点相连,容量为点权; 将所有负权点与汇点相连,容量为点权的相反数; 将原 ...
随机推荐
- php-get和post请求
1.get请求 <?php //判断20130101是否是工作日 //工作日对应结果为 0, 休息日对应结果为 1, 节假日对应的结果为 2: $url='http://www.easybots ...
- Local storage htm5
使用本地存储,web应用可以在用户浏览器中本地存储数据. 在HTML5之前,应用数据存储必须使用cookie,包括每个服务端的请求,本地存储更加安全,并且可以存储大量的数据到本地,不影响网站的性能. ...
- C语言system()函数:执行shell命令
头文件:#include <stdlib.h> 定义函数:int system(const char * string); 函数说明:system()会调用fork()产生子进程, 由子进 ...
- Rsyslog 日志相关内容
[root@server vusers_home]# rpm -ql rsyslog|more ###.so结尾为模块,模块有分im为输入模块,om 为输出模块/etc/logrotate ...
- Update 出现在的问题
报错提示:之前的操作没有完成,运行deanup被打断,请先执行Cleanup方法. 正常右键点击Cleanup,如果只让默认值勾选,可能还是会报这个错.所以正确操作如下: 全部选中再点击OK,这样就可 ...
- 微信小程序内嵌网页能力开放 小程序支持内嵌网页文档说明
为了方便开发者灵活配置微信小程序,张小龙现在开放了小程序的内嵌网页功能,这是一个非常大的惊喜啊,以后意味着你只要开放一个手机端网站,就可以制作一个小程序了哦.操作方法1.开发者登录微信小程序后台,选择 ...
- Spring Boot配置多个DataSource
使用Spring Boot时,默认情况下,配置DataSource非常容易.Spring Boot会自动为我们配置好一个DataSource. 百牛信息技术bainiu.ltd整理发布于博客园 如果在 ...
- ftp主要流程
判断是否是root用户,若不是则提示并退出. 建立server socket. 等待用户连接,并建立相应用户的子进程.
- Ubuntu 16.04使用chrome闪屏
使用Chrome的时候上端经常出现闪动的情况, 但是速度特别快, 根本无法截图, 感觉特别扎心, 以为自己的电脑出现问题了或者显卡驱动出现问题了, 后来才发现问题, 只需要关闭Chrome的硬件加速就 ...
- js正则匹配字符串
这里我第一时间想到的就是用 js 的search 和 match ,其中最常见的是match: 1. str.search(regexp):search()方法不支持全局搜索,因为会忽略正则表达式参数 ...