HDU_4971_A simple brute force problem.(最大权闭合图)
来源:互联网 发布:华为大数据案例分析 编辑:程序博客网 时间:2024/05/01 15:24
题型:网络流
题意:
有n个项目,m个技术问题。做项目会挣钱,解决技术问题需要花钱。想要完成一个项目,就要解决对应的技术问题,求能获得的最多的利润。
分析:
赤果果的最大权闭合图问题。
先学习一下闭合图的概念。
闭合图就是,对于一个点集V,如果他们的所有的边所指向的点都在点集V中,则这个点集加上他们的边是闭合图。
如图:
1、2、4、5组成的图就是闭合图,3、4、5组成的图也是闭合图,而1、2、5组成的图就不是闭合图,因为点1有一条边连出去了。
每个点有权值正负零都有可能,选某个点u,如果必须选v,则我们设u,v有一条有向边。最后要我们有一种选取方案使得所选的点权值和最大。这就是最大权闭合图。
解法用最大流来解。
建图方法是:s源点到所有正权点连流量为那个点权值的边,所有负权点到汇点t连流量为负权绝对值的边。原来图中的依赖关系正常建边,流量定为inf。
跑出来的最大流就是最小割。用所有正权的和减去最小割就是可获得的最大权。
证明:
因为中间的都是inf,所以最小割肯定是割到与s连的或者与t连的边。那么就是我们选择一些正权或者负权,并且我们都是选小的。也就是说对于正权到s这里,如果正权很小,并且选他就必须选一些负权很大的边,那么我们在最小割中也会选这个正权小的,使得st不连通。反之,如果负权那里小,我们就会选择割负权。最后正权的总和减去最小割。
对于本题,可以清楚的看出可以转化为最大权闭合图来求解:
首先由于技术问题的图可能形成环,所以需要先缩点,建成新的图,下面构造网络流的图。
源点S与每个项目建边,权值为项目的收入;
项目与所对应的技术问题建边,权值为inf;
技术问题与技术问题之间,有前驱关系的技术问题建边,例如i是j的前驱,则j->i,权值为inf;
每一个技术问题与汇点T建边,权值为技术问题的花费。
最大利润等于完成所有项目的收入减去最大流。
代码:
一不小心突破本人单个文件代码长度上限,9000+B不解释~
#include<iostream>#include<cstdio>#include<cmath>#include<stack>#include<queue>#include<cstdlib>#include<algorithm>#include<cstring>#define mt(a,b) memset(a,b,sizeof(a))using namespace std;const int M = 123456;const int inf = 0x7f7f7f7f;int profit[30],cost[60];class Tarjan { ///Tarjan 算法有向图强连通分量缩点public: struct E { int u,v,next; } e[M<<4]; ///Bcnt 强连通分量的个数,num 个分量的点数,belong属于哪个分量 int le,head[M],Index,Bcnt,num[M],belong[M],dfn[M],low[M]; bool instack[M]; stack<int> s; void tarjan(int u) { dfn[u]=low[u]=++Index; instack[u]=true; s.push(u); int v; for(int i=head[u]; ~i; i=e[i].next) { v=e[i].v; if(!dfn[v]) { tarjan(v); low[u]=min(low[u],low[v]); } else if(instack[v]) { low[u]=min(low[u],dfn[v]); } } if(dfn[u]==low[u]) { Bcnt++; do { v=s.top(); s.pop(); instack[v]=false; belong[v]=Bcnt; num[Bcnt]++; } while(u!=v); } } void init() { le=Index=Bcnt=0; mt(head,-1); mt(num,0); mt(dfn,0); mt(low,0); mt(instack,0); while(!s.empty()) s.pop(); } void add(int u,int v) { e[le].u=u; e[le].v=v; e[le].next=head[u]; head[u]=le++; } void solve(int n) { for(int i=1; i<=n; i++) { if(!dfn[i]) { tarjan(i); } } } int getbcnt() { return Bcnt; } int getbelong(int id) { return belong[id]; } int getnum(int id) { return num[id]; }} gx;class Dinic { //最大流 struct E { int u,v,next,flow; } e[M<<1]; int le,flow,head[M],temp[M],cur[M],level[M],path[M]; bool used[M]; queue<int> q;public: int getflow() { return flow; } bool bfs(int s,int t) { mt(level,-1); while(!q.empty()) q.pop(); q.push(s); level[s]=1; while(!q.empty()) { int u=q.front(); q.pop(); for(int i=head[u]; ~i; i=e[i].next) { int v=e[i].v; if(level[v]==-1&&e[i].flow) { level[v]=level[u]+1; q.push(v); if(v==t) return true; } } } return false; } void init() { le=0; mt(head,-1); } void add(int u,int v,int flow) { e[le].u=u; e[le].v=v; e[le].flow=flow; e[le].next=head[u]; head[u]=le++; e[le].u=v; e[le].v=u; e[le].flow=0; e[le].next=head[v]; head[v]=le++; } void solve(int s,int t) { int p,now,tempp; bool flag; flow=0; while(bfs(s,t)) { for(int i=0; i<M; i++) { temp[i]=head[i]; used[i]=true; } p=1; path[p]=s; while(p) { int u=path[p]; if(u==t) { now=inf; for(int i=1; i<p; i++) { now=min(now,e[cur[path[i]]].flow); } flow+=now; for(int i=1; i<p; i++) { e[cur[path[i]]].flow-=now; e[cur[path[i]]^1].flow+=now; if(!e[cur[path[i]]].flow) tempp=i; } p=tempp; } else { flag=false; for(int i=temp[u]; ~i; i=e[i].next) { int v=e[i].v; if(used[v]&&e[i].flow&&level[u]+1==level[v]) { cur[u]=i; temp[u]=e[i].next; flag=true; path[++p]=v; break; } } if(flag) continue; p--; used[u]=false; } } } }} ts;struct project_problems { int num; int question[55];} project[25];int Map[55][55];struct Node { int value;} newgraph[55];int main() {// freopen("in.txt","r",stdin);// freopen("out.txt","w",stdout); int _,cas = 0; int n,m; int allprofit; scanf("%d",&_); while(_--) { scanf("%d%d",&n,&m); allprofit = 0; for(int i=0; i<n; i++) { scanf("%d",&profit[i]); allprofit += profit[i]; } for(int i=0; i<m; i++) { scanf("%d",&cost[i]); } ///网络流初始化 ts.init(); ///缩点初始化 gx.init(); ///输入项目的问题 for(int i=0; i<n; i++) { int num; scanf("%d",&num); project[i].num = num; for(int j=0; j<num; j++) { scanf("%d",&project[i].question[j]); } } ///输入problems之间的关系 int tmp; for(int i=0; i<m; i++) { for(int j=0; j<m; j++) { scanf("%d",&tmp); Map[i][j] = tmp; if(tmp == 1) { gx.add(i+1,j+1); } } } ///缩点 gx.solve(m);// printf("jihenum======%d\n",gx.getbcnt()); ///建成新的图 for(int i=0; i<=m; i++) { newgraph[i].value = 0; } for(int i=0; i<m; i++) { newgraph[gx.getbelong(i+1)].value += cost[i]; }// puts("******************");// for(int i=1;i<=gx.getbcnt();i++){// printf("%d ",newgraph[i].value);// }// puts("");// puts("******************"); ///网络流建图 ///源点S为n+m+1 ///汇点T为n+m+2 int s = n+m+1; int t = n+m+2; ///S与project连接 for(int i=0; i<n; i++) { ts.add(s,i,profit[i]); } ///project与problem建图 for(int i=0; i<n; i++) { for(int j=0; j<project[i].num; j++) { project[i].question[j] = gx.getbelong(project[i].question[j]+1); } sort(project[i].question,project[i].question+project[i].num); project[i].num = unique(project[i].question,project[i].question+project[i].num) - project[i].question; for(int j=0; j<project[i].num; j++) { ts.add(i,project[i].question[j]+n,inf); } }// puts("**************************");// for(int i=0;i<n;i++){// for(int j=0;j<project[i].num;j++){// printf("%d ",project[i].question[j]);// }// puts("");// }// puts("**************************"); bool flag[55][55]; mt(flag,false); ///problem与problem建图 for(int i=0; i<m; i++) { for(int j=0; j<m; j++) { if(gx.getbelong(i+1)!=gx.getbelong(j+1) && Map[i][j]==1 && !flag[gx.getbelong(i+1)][gx.getbelong(i+1)]) { ts.add(gx.getbelong(i+1)+n,gx.getbelong(j+1)+n,inf); flag[gx.getbelong(i+1)][gx.getbelong(j+1)] = true; } } } ///problem与T连接 for(int i=1; i<=gx.getbcnt(); i++) {// printf("i=%d t cost =%d\n",i,newgraph[i].value); ts.add(i+n,t,newgraph[i].value); } ///跑最大流 ts.solve(s,t);// printf("flow = %d\n",ts.getflow()); printf("Case #%d: %d\n",++cas,allprofit - ts.getflow()); } return 0;}/**1233 510 10 101 2 3 4 52 2 33 1 2 35 0 1 2 3 40 1 0 0 00 0 1 0 00 0 0 1 00 1 0 0 10 0 0 0 0122 310 108 10 61 01 20 1 00 0 00 0 010010 2060 65 10 48 31 14 14 4 92 305 7 6 43 24 10 30 40 5 3 28 31 43 25 42 16 43 45 27 302 1 116 11 6 2 3 17 1515 6 4 13 16 7 8 10 2 3 1 11 17 0 18 52 4 817 11 14 18 7 0 10 12 17 8 9 2 16 3 15 1 6 48 10 12 16 6 2 19 3 137 3 17 18 12 15 2 163 0 3 82 4 82 9 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 1 1 0 0 0 0 1 0 0 0 1 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 01 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 01 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 01 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 00 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 1 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 00 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 00 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0*/
- HDU_4971_A simple brute force problem.(最大权闭合图)
- hdu4971A simple brute force problem.【最大权闭合图】
- HDU 4971 A simple brute force problem.(最大权闭合)
- hdu4917 A simple brute force problem.(最大权闭合)
- HDU 4971 A simple brute force problem. 强连通缩点+最大权闭合图
- 【HDU】4971 A simple brute force problem. 强连通缩点+最大权闭合子图
- HDU 4971 A simple brute force problem. 最大权闭合图
- HDU 4971 A simple brute force problem.(最小割,最大权闭合图)
- hdu 多校联合 4971 A simple brute force problem.(最大权闭合图)
- HDU 4971 A simple brute force problem 最大权闭合图
- hdoj 4971 A simple brute force problem. 【最大权闭合图 --> 最小割】
- hdu - 4971 - A simple brute force problem.(最大权闭合图)
- HDU 4971 A simple brute force problem.最大权闭合图
- HDU 4971 A simple brute force problem.(最小割,最大权闭合图)
- HDU 4971 A simple brute force problem.(最小割---最大权闭合)
- HDU 4971 A simple brute force problem. 最小割 最大权闭合
- HDU5772 String problem 最大权闭合图
- HDU-4971-A simple brute force problem.
- 改变导航栏的颜色 ios6.0 ios7
- window下hadoop-2.2.0应用程序开发_java
- Android构建boot.img(一):root目录与ramdisk.img的生成
- 第一章—介绍原子性,条件同步以及自旋和阻塞的区别
- 索引的十一种功能
- HDU_4971_A simple brute force problem.(最大权闭合图)
- ORA-01552 :非系统表空间 'xxxx'不能使用系统回退段
- FAT学习笔记(五)——FAQ
- Android构建boot.img(二):kernel的拷贝与打包
- Mysql 数据库添加数据问题(版本问题)
- 文摘---忙碌的时空分一丝看看
- 一致性hash算法
- IO - 同步,异步,阻塞,非阻塞
- svn: Can't convert string from 'UTF-8' to native encoding: