zoukankan      html  css  js  c++  java
  • 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("
    ");
            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
    ",temp);
            printf("%d",ans[0]);
            for(i=1;i<temp;i++)
                printf(" %d",ans[i]);
            printf("
    ");
        }
        return 0;
    }
  • 相关阅读:
    ls: cannot open directory .: Permission denied
    postman报错:Could not get any response
    IO流的继承关系
    吸顶效果
    linux报错:ls command not found
    内存寻址能力与CPU的位宽有关系吗?
    CPU与内存
    SQL语言的分类
    32位CPU和64位CPU 区别
    linux添加环境变量
  • 原文地址:https://www.cnblogs.com/wangfang20/p/3204355.html
Copyright © 2011-2022 走看看