zoj 2676(0-1)分数规划
2011-08-11 17:17
225 查看
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1676
题意描述:07年集训队胡伯涛论文题,求边割的权值和除以边的条数的值最小(注意这个割不是我们平常所说的割,它除了包含我们平常所说的割,还可能包含其他的边,这样有可能使得所求的平均值更小);
解决:0-1分数规划的问题可以转化为最小割模型来解决,题目解决的问题就是minize x=
,则设g(x)=
(x即为r)因为ci只能取0或1所以能转为最小割模型模型,ci为组成一个
向量,wi组成一个行向量;
定理1:当且仅当g(x)=0时x的能达到最小,所以可以枚举x的值从而使g(x)为0则得到解
定理2:函数g(x)为单调递减的函数,所以在枚举x的时候:
g(x)>0 则将x的值减小
g(x)<0则将x的值增大
g(x)=0则得到结果
那么现在的任务显然是求g(x)然后判断与0的关系,那么如何求g(x)呢?将原来图中边的权值都改为w-x*c,因为是0-1归回,c只能去0或者1,那么就可以将权值改为w-x,这样后如果w-x为负则说明该边一定在割内,为什么呢?因为该边加上去之后会使求得的割更小,之后为正的建图后求最小割即可,还有个恶心的问题需要注意精度!
贴代码先:
总结与感想:这题写了好久,都是精度惹的祸,不会处理,个人理解精度问题就是将0周围一定范围的数都当成0对待,该题参照了yw大神的代码,在此表示感谢,开始贴了个dinic模板求最小割居然tle了,也没明白为什么会tle,最后果断换成ISAP才过
题意描述:07年集训队胡伯涛论文题,求边割的权值和除以边的条数的值最小(注意这个割不是我们平常所说的割,它除了包含我们平常所说的割,还可能包含其他的边,这样有可能使得所求的平均值更小);
解决:0-1分数规划的问题可以转化为最小割模型来解决,题目解决的问题就是minize x=
,则设g(x)=
(x即为r)因为ci只能取0或1所以能转为最小割模型模型,ci为组成一个
向量,wi组成一个行向量;
定理1:当且仅当g(x)=0时x的能达到最小,所以可以枚举x的值从而使g(x)为0则得到解
定理2:函数g(x)为单调递减的函数,所以在枚举x的时候:
g(x)>0 则将x的值减小
g(x)<0则将x的值增大
g(x)=0则得到结果
那么现在的任务显然是求g(x)然后判断与0的关系,那么如何求g(x)呢?将原来图中边的权值都改为w-x*c,因为是0-1归回,c只能去0或者1,那么就可以将权值改为w-x,这样后如果w-x为负则说明该边一定在割内,为什么呢?因为该边加上去之后会使求得的割更小,之后为正的建图后求最小割即可,还有个恶心的问题需要注意精度!
贴代码先:
#include<iostream> #include<cstring> #include<cstdio> #include<cmath> using namespace std; const int N = 150; const int M = 2000; const double eps = 1e-5; const double Max = 0xfffffff; struct node { int u,v, next; double w; }edge1[M],edge[M]; int first1 ,first ,e1,e; int n,vis ,flag[M],level ; int Que ; int S,T; int dist ,now ,cnt ,pre ; double cur ; void add1(int u, int v ,double w) { edge1[e1].v=v; edge1[e1].w = w; edge1[e1].next =first1[u]; first1[u]=e1++; } void add(int u, int v, double w) { edge[e].u=u; edge[e].v = v; edge[e].w = w; edge[e].next = first[u]; first[u] = e++; edge[e].u=v; edge[e].v = u; edge[e].w = 0; edge[e].next=first[v]; first[v]=e++; } void dfs(int u) { vis[u]=1; for(int i = first[u];i!=-1;i=edge[i].next) { int v = edge[i].v; if(vis[v]==0&&edge[i].w>eps) dfs(v); } } double SAP() { int i,j,k;double flow=Max,tot=0,min; bool found; memset(pre,-1,sizeof(pre)); memset(cnt,0,sizeof(cnt)); memset(now,-1,sizeof(now)); memset(dist,0,sizeof(dist)); i=S; cnt[0]=T+1; while(dist[S]<=T) { cur[i]=flow; found=false; if(now[i]==-1) k=first[i]; else k=now[i]; for(;k!=-1;k=edge[k].next) { j=edge[k].v; if(edge[k].w>eps&&dist[j]+1==dist[i]) { found=true; pre[j]=k; now[i]=k; i=j; if(edge[k].w<flow) flow=edge[k].w; if(i==T) { tot+=flow; while(i!=S) { edge[pre[i]].w-=flow;//注意是pre[i] edge[pre[i]^1].w+=flow; i=edge[pre[i]].u;//e[pre[i]].u } flow=Max; } break; } } if(found) continue; if(--cnt[dist[i]]==0) break; for(min=T,k=first[i];k!=-1;k=edge[k].next) { j=edge[k].v; if(edge[k].w>eps&&min>dist[j]) { now[i]=k; min=dist[j]; } } dist[i]=min+1; cnt[dist[i]]++; if(i!=S) { i=edge[pre[i]].u; flow=cur[i]; } } return tot; } int main () { int u, v, m,i,num; double w,max,right,left,sum,maxflow,mid; while(scanf("%d%d",&n,&m)!=EOF) { e1 = 0; memset(first1,-1,sizeof(first1)); max=0; for(i = 0;i<m;i++) { scanf("%d%d%lf",&u,&v,&w); if(max < w) max=w; add1(u,v,w); add1(v,u,w); } left=0;right=max; S=1; T = n; int ans=0; while(left<right||fabs(left-right)<eps) //枚举每个结果值然后判断是否为最优 { ans++; mid = (left+right)/2.0; e=0; sum =0; memset(first,-1,sizeof(first)); memset(flag,0,sizeof(flag)); for(u = 1;u<=n;u++) for(i = first1[u]; i!=-1;i=edge1[i].next) if(edge1[i].w-mid<0&&!flag[i^1]) //若权值为负那么一定取,因为是邻接表建图一条无向边被当成两条有向边建,而sum只能算一次,所以需要flag来标记一下 { sum+=edge1[i].w-mid; flag[i]=1;flag[i^1]=1; } else if(edge1[i].w-mid>0)//因为取零的时候对结果无影响所以建图的时候可以省略 add(u,edge1[i].v,edge1[i].w-mid); maxflow = SAP(); sum+=maxflow; if(fabs(sum)< eps) break; else if(sum < 0) right=mid-eps; else left=mid+eps; } memset(vis,0,sizeof(vis)); dfs(1); for(i=1;i<=n;i++) for(e = first1[i];e!=-1;e=edge1[e].next) if(vis[i]&&!vis[edge1[e].v]) flag[e]=1; num=0; for(i=0;i<e1;i+=2) if(flag[i]||flag[i+1]) num++; printf("%d\n",num); for(i=0;i<e1;i+=2) if(flag[i]||flag[i+1]) printf("%d ",i/2+1); printf("\n"); } return 0; }
总结与感想:这题写了好久,都是精度惹的祸,不会处理,个人理解精度问题就是将0周围一定范围的数都当成0对待,该题参照了yw大神的代码,在此表示感谢,开始贴了个dinic模板求最小割居然tle了,也没明白为什么会tle,最后果断换成ISAP才过
相关文章推荐
- zoj 2676 Network Wars 0-1分数规划+最小割
- ZOJ 2676 Network Wars ★(最小割算法介绍 && 01分数规划)
- 【01分数规划】 ZOJ 2676 Network Wars
- ZOJ-2676-Network Wars(01分数规划+最小割)
- ZOJ 2676 Network Wars 最小割 分数规划
- ZOJ 2676 Network Wars[01分数规划]
- 【ZOJ】2676 Network Wars 01分数规划+最小割
- zoj 2676 Network Wars(01分数规划+最小割)
- zoj 2676 Network Wars 【0-1分数规划 + 最小割】 【吃一堑长一智】
- zoj 2676 网络流+01分数规划
- zoj 2676 Network Wars(01分数规划+最大流)
- ZOJ 2676 Network Wars(01分数规划-二分+最小割)
- 【ZOJ 2676】Network Wars 网络战争 网络流 01分数规划
- ZOJ 2676 01分数规划 最小割
- zoj 2676 Network Wars(01分数规划+网络流)
- zoj 2676 Network Wars(最小割,01分数规划)
- ZOJ 2676 分数规划
- zoj 2676 Network Wars 最小割+0-1分数规划
- ZOJ 2676 Network Wars ★(最小割算法介绍 && 01分数规划)
- POJ 2976/ZOJ 3068 Dropping tests 01分数规划