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;
}

 

posted @ 2013-07-21 21:54  fangguo  阅读(208)  评论(0编辑  收藏  举报