zoukankan      html  css  js  c++  java
  • poj2112 最大流

    我用Dinic写的。G++ 1800ms 很慢,c++直接超时。优化后的 141ms,很快!

    对于此题,建图方法很巧妙,通常想到求距离,那就会朝距离的方向建图,但是这题根据牛个数来建图,然后二分距离。

      先求出任意点之间的最短距离。对于挤奶器,牛,很明显的分为2部分。挤奶器的牛来自牛这部分。先另外设源点和汇点。对于牛部分,都与源点相连,容量为1。然后二分

    距离,对于挤奶器和牛之间的容量,如果挤奶器和牛之间的距离小于或等于二分的距离,那么此路可以通过牛。然后挤奶器与汇点之间的容量为m值。这样图就建完了。然后Dinic

    求最大流(此时最大流的值表示牛的个数),如果此时最大流的值>=c,即满足牛的个数,那这个距离是可以的,然后继续二分,知道得到结果。

    #include<stdio.h>
    #include<string.h>
    #include<queue>
    #define maxn 300
    #define INF 99999999
    using namespace std;
    int map[maxn][maxn],dis[maxn][maxn],vis[maxn];
    int k,c,m;
    int min(int x,int y)
    {
        return x<y?x:y;
    }
    void floyd(int n)
    {
        int i,j,t;
        for(t=1;t<=n;t++)
        {
            for(i=1;i<=n;i++)
            {
                for(j=1;j<=n;j++)
                {
                    if(dis[i][j]>dis[i][t]+dis[t][j])
                        dis[i][j]=dis[i][t]+dis[t][j];
                }
            }
        }
    }
    void makemap(int maxval,int n)
    {
        int i,j;
        memset(map,0,sizeof(map));
        for(i=1;i<=k;i++)
            map[i][n+1]=m;
        for(i=k+1;i<=n;i++)
            map[0][i]=1;
        for(i=k+1;i<=n;i++)
        {
            for(j=1;j<=k;j++)
            {
                if(dis[i][j]<=maxval)
                    map[i][j]=1;
            }
        }
    }
    int BFS(int n)
    {
        int i,j;
        queue<int>q;
        memset(vis,-1,sizeof(vis));
        vis[0]=0;
        q.push(0);
        while(!q.empty())
        {
            int t=q.front();
            q.pop();
            for(i=0;i<=n+1;i++)
            {
                if(vis[i]<0&&map[t][i])
                {
                    q.push(i);
                    vis[i]=vis[t]+1;
                }
            }
        }
        if(vis[n+1]>0)
            return 1;
        return 0;
    }
    int dfs(int u,int low,int n)
    {
        int i,j,a;
        if(u==n)
            return low;
        for(i=0;i<=n;i++)
        {
            if(vis[i]==vis[u]+1&&map[u][i])
            {
                a=dfs(i,min(low,map[u][i]),n);
                if(!a)continue;
                map[u][i]-=a;
                map[i][u]+=a;
                return a;
            }
        }
        return 0;
    }
    int main()
    {
        int i,j,n;
        while(scanf("%d%d%d",&k,&c,&m)!=EOF)
        {
            n=k+c;
            for(i=1;i<=k+c;i++)
            {
                for(j=1;j<=k+c;j++)
                {
                    scanf("%d",&dis[i][j]);
                    if(dis[i][j]==0)//不连通给予无穷,防止floyd出现问题
                        dis[i][j]=INF;
                }
            }
            floyd(n);
    
            /*for(i=1;i<=k+c;i++)
            {
                for(j=1;j<=k+c;j++)
                {
                    printf("%d ",dis[i][j]);
                }
                printf("
    ");
            }*/
    
            int L=0,R=40000;
            int ans=0;
            int rt=0;
            while(L<=R)//二分答案
            {
                rt=0;
                int mid=(L+R)/2;
                makemap(mid,n);//根据二分的值建图
                while(BFS(n))
                {
                    int fa=dfs(0,INF,n+1);
                    if(!fa) break;;
                    rt+=fa;
                }
                if(rt>=c)
                {
                    R=mid-1;
                    ans=mid;
                }
                else 
                {
                    L=mid+1;
                }
            }
            printf("%d
    ",ans);
        }
    }

    优化后:

    #include<stdio.h>
    #include<string.h>
    #include<queue>
    #define maxn 300
    #define INF 99999999
    using namespace std;
    int map[maxn][maxn],dis[maxn][maxn],vis[maxn];
    int k,c,m;
    int min(int x,int y)
    {
        return x<y?x:y;
    }
    void floyd(int n)
    {
        int i,j,t;
        for(t=1;t<=n;t++)
        {
            for(i=1;i<=n;i++)
            {
                for(j=1;j<=n;j++)
                {
                    if(dis[i][j]>dis[i][t]+dis[t][j])
                        dis[i][j]=dis[i][t]+dis[t][j];
                }
            }
        }
    }
    void makemap(int maxval,int n)
    {
        int i,j;
        memset(map,0,sizeof(map));
        for(i=1;i<=k;i++)
            map[i][n+1]=m;
        for(i=k+1;i<=n;i++)
            map[0][i]=1;
        for(i=k+1;i<=n;i++)
        {
            for(j=1;j<=k;j++)
            {
                if(dis[i][j]<=maxval)
                    map[i][j]=1;
            }
        }
    }
    int BFS(int n)
    {
        int i,j;
        queue<int>q;
        memset(vis,-1,sizeof(vis));
        vis[0]=0;
        q.push(0);
        while(!q.empty())
        {
            int t=q.front();
            q.pop();
            for(i=0;i<=n+1;i++)
            {
                if(vis[i]<0&&map[t][i])
                {
                    q.push(i);
                    vis[i]=vis[t]+1;
                }
            }
        }
        if(vis[n+1]>0)
            return 1;
        return 0;
    }
    int dfs(int u,int low,int n)
    {
        int i,j,a,used=0;
        if(u==n)
            return low;
        for(i=0;i<=n&&used<low;i++)
        {
            if(vis[i]==vis[u]+1&&map[u][i])
            {
                a=dfs(i,min(low-used,map[u][i]),n);//多路增广
                if(!a)continue;
                map[u][i]-=a;
                map[i][u]+=a;
                used+=a;
            }
        }
        if(!used)
            vis[u]=-1;
        return used;
    }
    int main()
    {
        int i,j,n;
        while(scanf("%d%d%d",&k,&c,&m)!=EOF)
        {
            n=k+c;
            for(i=1;i<=k+c;i++)
            {
                for(j=1;j<=k+c;j++)
                {
                    scanf("%d",&dis[i][j]);
                    if(dis[i][j]==0)//不连通给予无穷,防止floyd出现问题
                        dis[i][j]=INF;
                }
            }
            floyd(n);
    
            /*for(i=1;i<=k+c;i++)
            {
                for(j=1;j<=k+c;j++)
                {
                    printf("%d ",dis[i][j]);
                }
                printf("
    ");
            }*/
    
            int L=0,R=40000;
            int ans=0;
            int rt=0;
            while(L<=R)//二分答案
            {
                rt=0;
                int mid=(L+R)/2;
                makemap(mid,n);//根据二分的值建图
                while(BFS(n))
                {
                    int fa=dfs(0,INF,n+1);
                    if(!fa) break;;
                    rt+=fa;
                }
                if(rt>=c)
                {
                    R=mid-1;
                    ans=mid;
                }
                else
                {
                    L=mid+1;
                }
            }
            printf("%d
    ",ans);
        }
    }
  • 相关阅读:
    R获取指定GO term和KEGG pathway的gene list基因集
    统计和数学中常见的定理汇总 | 大数定律 | 中心极限定理
    Genome Aggregation Database (gnomAD) 简介 | 参考人群等位基因频率数据库
    SC3聚类 | 拉普拉斯矩阵 | Laplacian matrix | 图论 | R代码
    Bayesian Statistics for Genetics | 贝叶斯与遗传学
    似然函数 | 最大似然估计 | likelihood | maximum likelihood estimation | R代码
    如何选题?| 什么样的科学问题 | 研究项目才是有意义的?| scientific method
    响应面分析 | response surface analysis | R代码
    乌龙茶生产过程中挥发性成分吲哚的形成 | Formation of Volatile Tea Constituent Indole During the Oolong Tea Manufacturing Process
    PPI | protein-protein interaction | 蛋白互作分析 | gene interaction | 基因互作
  • 原文地址:https://www.cnblogs.com/sweat123/p/4833944.html
Copyright © 2011-2022 走看看