博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
POJ 2152 Destroying The Graph【最小点权覆盖+最小割】
阅读量:6245 次
发布时间:2019-06-22

本文共 3064 字,大约阅读时间需要 10 分钟。

题意: 有一个有 N 个节点M 条边的的有向图,每个点对应两种操作:

          将该点所有入边删除 ‘+’ ,对应一个花费,将该点所有出边删除 ‘ - ’亦对应一个花费

          问如何操作将所有边删除使得花费的总和最小。

分析:  建图:

           将每个点拆分成两个点, i(左点) 和 i+n(右点) ,

           建立一个源点 s=0,汇点 u=2*n+1

           在源点和每个点左面的点连一条边,容量为删除出边的费用

           在汇点和每个点右面的点连一条边,容量为删除入边的费用

           如果有 u 到 v 的边,在u 和 v +n 之间连一条边,容量为无穷大

           求出最大流即最小割

           从源点深搜找出残流不为 0 的点,把这些点标记掉,剩下的为标记的点即为删除的顶点。

 

#include
#include
#include
#define INF 0x1f1f1f1f#define min(a,b)(a)<(b)?(a):(b)#define clr(x)memset(x,0,sizeof(x))#define maxn 210struct node{ int c,next,to;}e[100000];int tot;int head[maxn];void add(int s,int t,int flow){ e[tot].to=t; e[tot].c=flow; e[tot].next=head[s]; head[s]=tot++;}int max_flow(int st,int end,int n){ int numh[maxn],h[maxn],edge[maxn],pre[maxn]; int cur_flow,maxflow=0,u,tmp,neck,i; clr(h); clr(numh); memset(pre,0xff,sizeof(pre)); for(i=0;i<=n;i++) edge[i]=head[i]; numh[0]=n+1; u=st; while(h[st]
e[edge[i]].c) { neck=i; cur_flow=e[edge[i]].c; } for(i=st;i!=end;i=e[edge[i]].to) { tmp=edge[i]; e[tmp].c-=cur_flow; e[tmp^1].c+=cur_flow; } maxflow+=cur_flow; u=neck; } for(i=edge[u];i!=-1;i=e[i].next) if(e[i].c&&h[u]==h[e[i].to]+1) break; if(i!=-1) { edge[u]=i; pre[e[i].to]=u; u=e[i].to; } else { if(--numh[h[u]]==0) break; edge[u]=head[u]; for(tmp=n,i=head[u];i!=-1;i=e[i].next) if(e[i].c) tmp=min(tmp,h[e[i].to]); h[u]=tmp+1; ++numh[h[u]]; if(u!=st) u=pre[u]; } } return maxflow;}int v[maxn];void dfs(int r){ v[r]=1; int i,k; for(i=head[r];i!=-1;i=e[i].next) { k=e[i].to; if(!v[k]&&e[i].c) { v[k]=1; dfs(k); } }}int main(){ int i,n,m,s,u,p,a,b,res,num; while(scanf("%d%d",&n,&m)!=EOF) { s=0; u=2*n+1; memset(head,0xff,sizeof(head)); tot=0; for(i=1;i<=n;i++) { scanf("%d",&p); add(i+n,u,p); add(u,i+n,0); } for(i=1;i<=n;i++) { scanf("%d",&p); add(s,i,p); add(i,s,0); } while(m--) { scanf("%d%d",&a,&b); add(a,b+n,INF); add(b+n,a,0); } res=max_flow(s,u,n*2+1); num=0; clr(v); dfs(s); for(i=1;i<=n;i++) { if(!v[i]) num++; if(v[i+n]) num++; } printf("%d\n%d\n",res,num); for(i=1;i<=n;i++) { if(!v[i]) printf("%d -\n",i); if(v[i+n]) printf("%d +\n",i); } } return 0;}

 

转载于:https://www.cnblogs.com/dream-wind/archive/2012/08/11/2633912.html

你可能感兴趣的文章
中国电信10G PON演进研究成果卓著:为现网升级铺平道路 加速千兆时代到来
查看>>
家庭宽带市场竞争分析
查看>>
台媒:手机应用和免费wifi可瞬间泄露隐私
查看>>
QUnit单元测试文档
查看>>
手机网络电话(VOIP)大比拼
查看>>
华天动力OA系统全国渠道布局 20个城市分公司初露端倪
查看>>
我市智慧城市建设迈入快车道
查看>>
FSF 鼓励用户抛弃英特尔
查看>>
编程语言漫谈
查看>>
《Python数据科学实践指南》——0.4节一个简单的例子
查看>>
《树莓派学习指南(基于Linux)》——本章小结
查看>>
中国自主操作系统COS宣传片:很好很强大
查看>>
《SolidWorks 2017中文版机械设计从入门到精通)》——2.2 草图命令
查看>>
Google 开发新的开源系统 Fuchsia
查看>>
社区不是请客吃饭(二)不出国门也能参与OpenStack Summit
查看>>
FreeDOS 诞生二十周年
查看>>
新的 OpenID 基金会的董事会领导
查看>>
第十天:估算活动持续时间,类比估算,参数估算,自下而上估算,三点估算解析表...
查看>>
为什么我要垂直对齐代码(你也要如此!)
查看>>
《ANSYS Workbench 16.0超级学习手册》——1.4 本章小结
查看>>