zoj 2676 网络流+01分数规划
思路:
这题的结论得要看amber的论文,结论就是将求f(x)/b(x)最小转化为求min(f(x)-b(x)*λ),其中x为S集的解空间,f(x)为解的边权和,b(x)为解的边数,
λ=f(x)/b(x)。λ*为最优解,当且仅当(x属于S)∑min(f(x)-b(x)*λ)==0;故可以将原边权的权值改为w-λ;对λ进行二分枚举,找出答案。
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<vector> #define N 510 #define M 50010 #define inf 1e9 using namespace std; const double eps=1e-9; struct Edge{ int to,next,from; double val; }edge[M]; int Index[N],d[N],gap[N],e,vi[N]; void addedge(int from,int to,double val) { edge[e].from=from; edge[e].to=to; edge[e].val=val; edge[e].next=Index[from]; Index[from]=e++; edge[e].from=to; edge[e].to=from; edge[e].val=val; edge[e].next=Index[to]; Index[to]=e++; } int source,des,n,m; void DFS(int u) { vi[u]=1; int i,v; for(i=Index[u];i!=-1;i=edge[i].next) if(edge[i].val&&!vi[edge[i].to]) DFS(edge[i].to); } double dfs(int pos,double flow) { if(pos==des) return flow; int i,j,v,mind; double val,c,lv; mind=n-1;//初始最小标号为n-1 lv=flow; for(i=Index[pos];i!=-1;i=edge[i].next) { v=edge[i].to; val=edge[i].val; if(val) { if(d[v]+1==d[pos]) { c=min(lv,val);//对于该点的最小可行流 c=dfs(v,c); edge[i].val-=c;//更新剩余图 edge[i^1].val+=c; lv-=c; if(d[source]>=n)return flow-lv; if(lv==0) break; } if(d[v]<mind)mind=d[v];//找出与pos相连的点的最小标号 } } if(lv==flow)//没有找到增广路劲,进行标号更新 { --gap[d[pos]]; if(!gap[d[pos]]) d[source]=n; d[pos]=mind+1; ++gap[d[pos]]; } return flow-lv; } double sap(int st,int de) { source=st; des=de; memset(d,0,sizeof(d)); memset(gap,0,sizeof(gap)); gap[0]=n;//初始标号为0的有n个. double ans=0; while(d[st]<n) { ans+=dfs(st,inf); //cout<<d[st]<<endl; } return ans; } void init() { e=0; memset(Index,-1,sizeof(Index)); memset(vi,0,sizeof(vi)); } int main() { int i,j,a[N],b[N],w[N]; int lmin,rmax; int ff=0; while(scanf("%d%d",&n,&m)!=EOF) { if(ff)printf("\n"); ff=1; init(); lmin=inf; rmax=0; for(i=0;i<m;i++) { scanf("%d%d%d",a+i,b+i,w+i); lmin=min(lmin,w[i]); rmax=max(rmax,w[i]); } double l,r; l=lmin,r=rmax; double res=0; while(r-l>eps) { init(); double mid=(l+r)/2; res=0; for(i=0;i<m;i++) { if(w[i]<=mid) res+=w[i]-mid; else addedge(a[i],b[i],w[i]-mid); } res+=sap(1,n); if(res>0) l=mid; else r=mid; } init(); for(i=0;i<m;i++) { if(w[i]<=r) continue; addedge(a[i],b[i],w[i]-r); } sap(1,n); //cout<<r<<endl; //cout<<vi[2]<<" "<<vi[3]<<" "<<vi[4]<<" "<<vi[5]<<endl; DFS(1); vector<int> ans; for(i=0;i<m;i++) { if((w[i]<=r)||(vi[a[i]]&&!vi[b[i]])||(!vi[a[i]]&&vi[b[i]])) { ans.push_back(i+1); //cout<<edge[i].from<<" "<<edge[i].to<<endl; } } int temp=ans.size(); printf("%d\n",temp); printf("%d",ans[0]); for(i=1;i<temp;i++) printf(" %d",ans[i]); printf("\n"); } return 0; }