【最小割模型、01分数规划】zoj2676Network Wars
2015-08-05 21:33
369 查看
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2676
题目描述:对给定的无向图,n(2<=n<=100)(2<=n<=100)个点,m(1<=m<=400)(1<=m<=400)条边,源点为1,汇点为n。求一个割,使得该割边集的平均边权最小。
这道题在Amber大神的论文《最小割模型在信息学竞赛中的应用》中提出。建议大家去看一看。在13页。
论文地址
令xix_i表示第ii条边是否在割集中。当然权值为负的边直接放入割集中。
对于01分数规划问题,先构造一个新函数g(a)=min((w−ac)∗x)g(a)=min((w-ac)*x)其中w表示边的权值之和,c表示边的条数。
该函数是单调递减的,而最优解是当g(a)=0g(a)=0时得到。
如何check(mid)?
建图。
做一次最小割,判断割的容量为正还是为负。
特别注意,该题有浮点数运算,会存在浮点误差。(我就是在这里被坑了几次 %>_<%)
具体操作见代码。
题目描述:对给定的无向图,n(2<=n<=100)(2<=n<=100)个点,m(1<=m<=400)(1<=m<=400)条边,源点为1,汇点为n。求一个割,使得该割边集的平均边权最小。
这道题在Amber大神的论文《最小割模型在信息学竞赛中的应用》中提出。建议大家去看一看。在13页。
论文地址
令xix_i表示第ii条边是否在割集中。当然权值为负的边直接放入割集中。
对于01分数规划问题,先构造一个新函数g(a)=min((w−ac)∗x)g(a)=min((w-ac)*x)其中w表示边的权值之和,c表示边的条数。
该函数是单调递减的,而最优解是当g(a)=0g(a)=0时得到。
如何check(mid)?
建图。
做一次最小割,判断割的容量为正还是为负。
特别注意,该题有浮点数运算,会存在浮点误差。(我就是在这里被坑了几次 %>_<%)
具体操作见代码。
#include <iostream> #include <cstdio> #include <cstring> #define min(a,b) ((a)<(b)?(a):(b)) #define MAXN 405 #define MAXM 8005 #define eps 1e-4 using namespace std; int n ,m ,vd[MAXN] ,d[MAXN] ,s ,t ,uplimt ,a[MAXN] ,b[MAXN] ,temp[MAXN] ; bool vis[MAXN] ; double c[MAXN] ; struct node { int v ; double w ; node *next ,*back ; }edge[MAXM] ,*adj[MAXN] ,*code=edge ; void add(int a,int b,double c) { node *p=++code; p->v=b ,p->next=adj[a] ,p->w=c ,p->back=code+1 ; adj[a]=p ; p=++code ; p->v=a ,p->next=adj[b] ,p->w=0 ,p->back=code-1 ; adj[b]=p ; } double aug(int u,double augco) { if(u==t) return augco; int mind=uplimt ,v ; double augc=augco ,delta ; for(node *p=adj[u];p!=NULL;p=p->next) if(p->w >0) { v=p->v; if(d[u]==d[v]+1) { delta=min(augc,p->w); delta=aug(v,delta); augc-=delta ,p->w-=delta ,p->back->w+=delta ; if(d[s]>=uplimt)return augco-augc; if(augc<eps)break; //注意:不能写成if(!augc)break; } mind=min(mind,d[v]); } if(augco==augc) { --vd[d[u]]; if(vd[d[u]]==0) d[s]=uplimt ; d[u]=mind+1; ++vd[d[u]]; } return augco-augc; } double sap() { memset(d,0,sizeof d); memset(vd,0,sizeof vd); double flow=0; vd[0]=uplimt; while(d[s]<uplimt) flow+=aug(s,2147483647); return flow ; } bool check(double mid) { memset(adj,0,sizeof adj); code=edge ; s=1 ,t=n ,uplimt=t+1 ; double ans=0 ,tmp ; for(int i=0;i<m;++i) { tmp=c[i]-mid ; if(tmp>0) { add(a[i],b[i],tmp); add(b[i],a[i],tmp); } else ans+=tmp ; } ans+=sap(); return ans>=0; } void dfs(int u) { vis[u]=1; for(node *p=adj[u];p!=NULL;p=p->next) if(p->w>eps&&!vis[p->v]) dfs(p->v); } void work() { for(int i=0;i<m;++i) scanf("%d%d%lf",&a[i],&b[i],&c[i]); double mid ,ans=0 ,l=0.0 ,r=10000010.0 ; while(r-l>eps) { mid=(r+l)/2.0 ; if(check(mid)) ans=l=mid; else r=mid; } memset(vis,0,sizeof vis); dfs(s); double tmp ; int cnt=0 ; for(int i=0;i<m;++i) { tmp=c[i]-ans; if(tmp<0) temp[++cnt]=i+1; else if(vis[a[i]]^vis[b[i]]) temp[++cnt]=i+1; } printf("%d\n",cnt); for(int i=1;i<cnt;++i) printf("%d ",temp[i]); printf("%d\n",temp[cnt]); } int main() { while(~scanf("%d%d",&n,&m)) work(); return 0; }
相关文章推荐
- 介绍Unreal Engine 4中的接口(Interface)使用C++和蓝图
- hdu 1010 Tempter of the Bone
- Android Api Demos登顶之路(二十一)Secure Surface
- iOS-UICollectionViewLayout 自定义布局
- 在win7操作系统安装Oracle 10g,数据库安装不了的原因
- 【暑期基础2】A HDU 2026 首字母变大写
- 电脑购买
- Java IO
- 机器学习中的范数规则化之(二)核范数与规则项参数选择
- UICollectionView基本使用方法
- Binary Tree Maximum Path Sum
- 5.Python基础 缩进与选择的关系
- 姓名的“夫妻相”
- 水池数目
- List泛型集合
- zoj 2100 Seeding
- java大数模板
- UILabel
- 8.5学习总结
- Mysql 优化