网络流

 做比赛老是遇到网络流的题啊啊啊  开始搞起。。。

 Ford标号法   

poj 1149  PIGS

经典的构图题  一个人要卖猪  猪圈的钥匙在顾客手上  每个顾客有要买的猪的数量 求能卖出猪的最大数量

源点和每个猪圈的第一个顾客连边  边的权是猪圈中猪的数目  顾客跟汇点之间还有连边表示卖出猪的数目

做这种题构图真的很重要。。

代码如下。。。继续学习

<span style="font-family:KaiTi_GB2312;font-size:18px;"><span style="font-family:KaiTi_GB2312;">#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

#define INF 0xfffffff
#define MAXN 1010

int s,t;//源点 汇点
int cust[MAXN][MAXN];// 节点之间的容量
int flow[MAXN][MAXN];//节点之间的流量

void init()//初始化  构造网络流
{
    int M,N;//M是猪圈的数目 N是顾客的数目
    int num;//顾客拥有的钥匙数目
    int k;//第k个猪圈的钥匙
    int house[MAXN];//存储每个猪圈中猪的数目
    int last[MAXN];
    memset(last,0,sizeof(last)); memset(cust,0,sizeof(cust));
    scanf("%d%d",&M,&N);
    s=0; t=N+1;
    for(int i=1;i<=M;i++)//读入每个猪圈中猪的数目
        scanf("%d",&house[i]);
    for(int i=1;i<=N;i++)
    {
        scanf("%d",&num);
        for(int j=0;j<num;j++)
        {
            scanf("%d",&k);//读入钥匙序号
            if(last[k]==0)
                cust[s][i]=cust[s][i]+house[k];
            else //表示顾客i跟在顾客last[k]后面打开第k个猪圈
                cust[last[k]][i]=INF;
            last[k]=i;
        }
        scanf("%d",&cust[i][t]);//每个顾客到汇点的边 权值为顾客购买猪的数量
    }
}

void ford()
{
    //初始化为-2表示未标号 源点的标号为-1
    int prev[MAXN];
    int minflow[MAXN];
    //广度优先搜索遍历网络
    int que[MAXN];
    int qs,qe;
    int v;//当前检查的顶点
    int p;
    for(int i=0;i<MAXN;i++)
        for(int j=0;j<MAXN;j++)
            flow[i][j]=0;
    minflow[0]=INF;//源点标号的第二个分量为无穷大
    while(1)
    {
        for(int i=0;i<MAXN;i++)
            prev[i]=-2;
        prev[0]=-1;
        qs=0;  que[qs]=0;   qe=1;

        while(qs<qe&&prev[t]==-2)
        {
            v=que[qs];  qs++;
            for(int i=0;i<t+1;i++)
            {
//                cust[v][i]-flow[v][i]!=0能保证顶点i是v的邻接顶点切能进行标号
                if(prev[i]==-2&&(p=cust[v][i]-flow[v][i]))
                {
                    prev[i]=v;  que[qe]=i; qe++;
                    minflow[i]=(minflow[v]<p)?minflow[v]:p;
                }
            }
        }
        if(prev[t]==-2)  break;
        for(int i=prev[t],j=t;i!=-1;j=i,i=prev[i])
        {
            flow[i][j]+=minflow[t];
            flow[j][i]=-flow[i][j];
        }
    }
    p=0;
    for(int i=0;i<t;i++)
    {
        p+=flow[i][t];
    }
    printf("%d\n",p);
}

int main()
{
freopen("ceshi.txt","r",stdin);
    init();
    ford();

    return 0;
}
</span></span>


poj 1273  Drainage Ditches  HDU1532

排水沟题  就是计算从源点到汇点最大的水流速度

建图相对比较简单  用增广路的方法求最大流

代码:

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

#define MAXN 210
struct matrix
{
    int c,f;
};

matrix Edge[MAXN][MAXN];//流及容量 邻接矩阵
int M,N; //排水沟即弧的数目 汇合节点即顶点的数目
int s,t;//源点 汇点
int residual[MAXN][MAXN];  //残留网络
int que[MAXN*MAXN],qs,qe;
int pre[MAXN];//前一个顶点的序号
int vis[MAXN];
int maxflow,min_augument;//最大流流量 每次增广时的可改进量

void find_augument_path()//BFS求增光路
{
    int cu;
    memset(vis,0,sizeof(vis));
    qs=0; que[qs]=s;
    pre[s]=s;  vis[s]=1;  qe=1;
    memset(residual,0,sizeof(residual));
    memset(pre,0,sizeof(pre));
    while(qs<qe&&pre[t]==0)
    {
        cu=que[qs];
        for(int i=1;i<=N;i++)
        {
            if(vis[i]==0)
            {
                if(Edge[cu][i].c-Edge[cu][i].f>0)
                {
                    residual[cu][i]=Edge[cu][i].c-Edge[cu][i].f;
                    pre[i]=cu;   que[qe++]=i;  vis[i]=1;
                }
                else if(Edge[i][cu].f>0)//反向
                {
                    residual[cu][i]=Edge[i][cu].f;
                    pre[i]=cu;  que[qe++]=i;   vis[i]=1;
                }
            }
        }
        qs++;
    }
}

void augument_flow()//计算可改进量
{
    int i=t;
    if(pre[i]==0)
    {
        min_augument=0;
        return;
    }
    int j=0xfffffff;
    while(i!=s)//计算增光路上可改进量的最小值
    {
        if(residual[pre[i]][i]<j)  j=residual[pre[i]][i];
        i=pre[i];
    }
    min_augument=j;
}

void update_flow()//调整流量
{
    int i=t;
    if(pre[i]==0)  return;
    while(i!=s)
    {
        if(Edge[pre[i]][i].c-Edge[pre[i]][i].f>0)  Edge[pre[i]][i].f+=min_augument;
        else if(Edge[i][pre[i]].f>0)  Edge[pre[i]][i].f+=min_augument;
        i=pre[i];
    }
}

void solve()
{
    s=1;  t=N;
    maxflow=0;
    while(1)
    {
        find_augument_path();
        augument_flow();
        maxflow+=min_augument;
        if(min_augument>0)  update_flow();
        else return;
    }
}

int main()
{
//freopen("ceshi.txt","r",stdin);
    int u,v,c;
    while(scanf("%d%d",&M,&N)!=EOF)
    {
        memset(Edge,0,sizeof(Edge));
        for(int i=0;i<M;i++)
        {
            scanf("%d%d%d",&u,&v,&c);
            Edge[u][v].c+=c;//可能会有重边
        }
        solve();
        printf("%d\n",maxflow);
    }
    return 0;
}

 poj 2112  Optimal Milking

最优的挤奶牛方案  

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

#define MAX 300
#define INF 10000000

int dis[MAX][MAX];//任意连点间的最短路径
int map[MAX][MAX];//容量网络
bool sigh[MAX][MAX];//层次网络
bool used[MAX];
int K,C,n,M;

void Build_Graph(int min_max)//构建容量网络
{
    memset(map,0,sizeof(map));
    for(int i=K+1;i<=n;i++)  map[0][i]=1;
    for(int i=1;i<=K;i++)  map[i][n+1]=M;
    for(int i=K+1;i<=n;i++)
    {
        for(int j=1;j<=K;j++)
        {
            if(dis[i][j]<=min_max)   map[i][j]=1;
        }
    }
}

bool BFS()//BFS构造层次网络
{
    memset(used,0,sizeof(used));
    memset(sigh,0,sizeof(sigh));
    int que[100*MAX]={0};
    que[0]=0;
    used[0]=1;
    int t=1,f=0;
    while(f<t)
    {
        for(int i=0;i<=n+1;i++)
        {
            if(!used[i]&&map[que[f]][i])
            {
                que[t++]=i;
                used[i]=1;
                sigh[que[f]][i]=1;
            }
        }
        f++;
    }
    if(used[n+1])  return true;
    else  return false;
}

int DFS(int v,int sum)
{
    if(v==n+1)  return sum;
    int s=sum;
    for(int i=0;i<=n+1;i++)
    {
        if(sigh[v][i])
        {
            int t=DFS(i,min(map[v][i],sum));
            map[v][i]-=t;
            map[i][v]+=t;
            sum-=t;
        }
    }
    return s-sum;
}


int main()
{
    int L,R,mid,ans;
    while(scanf("%d%d%d",&K,&C,&M)!=EOF)
    {
        n=K+C;
        //Floyd算法 求任意两点间的最短距离
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
        {
            scanf("%d",&dis[i][j]);
            if(dis[i][j]==0)  dis[i][j]=INF;
        }
        for(int k=1;k<=n;k++)
            for(int i=1;i<=n;i++)
        {
            if(dis[i][k]!=INF)
            {
                for(int j=1;j<=n;j++)
                {
                    dis[i][j]=min(dis[i][k]+dis[k][j],dis[i][j]);
                }
            }
        }
        L=0;R=10000;
        //二分搜索
        while(L<R)
        {
            mid=(L+R)/2;
            ans=0;
            //Dinic算法求最大流
            Build_Graph(mid);//构建容量网络
            while(BFS())  ans+=DFS(0,INF);
            if(ans>=C)   R=mid;
            else L=mid+1;
        }
        printf("%d\n",R);
    }
    return 0;
}


//待续

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值