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("\n");
        }*/

        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\n",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("\n");
        }*/

        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\n",ans);
    }
}

 

posted @ 2015-09-23 23:46  sweat123  阅读(138)  评论(0编辑  收藏  举报