poj1273

Sample Input
5 4
1 2 40
1 4 20
2 4 20
2 3 30
3 4 10
Sample Output
50
题意
现在有m个池塘(从1到m开始编号,1为源点,m为汇点),及n条水渠,给出这n条水渠所连接的点和所能流过的最大流量,

//Ford-fulkerson算法 
//没有太多理解 只是暂时把代码背住了
//一直维护残余网络(包括正向边和逆向边)
//初始条件下,正向边的c等于原来c,逆向边的c=0;
//1、找一条增广路;
//2、更新残余网络;
//3、重复第一步,直到找不到新的能到达汇点的增广路
#include<cstdio>
#include<cstring>
#define min(a,b)((a)<(b)?a:b)
struct edge{int v,next,w;}e[10010];
int first[210],en=2;;
bool vis[210];
void addedge(int u,int v,int wi,int rw=0)
{  //en 从2开始,每读入一次会加两下,
   //因此互连的两点first【u】=first【v】^1 的en可以通过i^1变换
   //u 终点v起点 wi正向边权值rw逆向边权值
    e[en].v=v;e[en].next=first[u];e[en].w=wi;first[u]=en++;
    e[en].v=u;e[en].next=first[v];e[en].w=rw;first[v]=en++;//对称的美感
}
int dfs(int to,int t,int f)
{
    if(to==t)return f;vis[to]=true;//当前已访问
    for(int i=first[to];i!=-1;i=e[i].next)
    {
        if(!vis[e[i].v]&&e[i].w>0)
        {//在相连的点中找到还未访问的边的权值大于0的点
            int d=dfs(e[i].v,t,min(e[i].w,f));
            if(d>0)
            {
                e[i].w-=d;
                e[i^1].w+=d;
                return d;
            }
        }
    }
}
void out(int s,int t)
{
    int flow=0;int inf=10010;
    while(1)
    {   
        memset(vis,false,sizeof(vis));
        int f=dfs(s,t,inf);//每一次都是从源点到汇点
        if(f<=0){printf("%d\n",flow);break;}
        flow+=f;
    }
}
void input()
{
    int n,t,u,v,w;

    memset(first,-1,sizeof(first));
    scanf("%d%d",&n,&t);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        addedge(u,v,w,0);//反向边初值为0
    }
    int s=1;
    out(s,t);//源点和汇点
}
int main()
{
    input();
    return 0;
}
//dinic 算法
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define min(a,b)((a)<(b)?a:b)
using namespace std;
struct edge{int v,next,w;}e[10010];
int en=2,t,first[1010],s=1,current[1010];
void addedge(int u,int v,int w,int rw=0)
{
    e[en].v=v;e[en].next=first[u];e[en].w=w;first[u]=en++;
    e[en].v=u;e[en].next=first[v];e[en].w=rw;first[v]=en++;
}
int dis[1010],inf=2139062143;
int bfs()
{//先做bfs ,作出一颗树来,记录每一个节点的层次,
    int q[1010];
    memset(dis,127,sizeof(dis));//初始化的层次
    memset(q,0,sizeof(q));
    dis[s]=0;int tail=1,head=1;q[tail++]=s;//源点第0层
    while(head!=tail)
    {
        int hh=q[head++];
        for(int i=first[hh];i!=-1;i=e[i].next)
        {
            if(dis[e[i].v]==inf&&e[i].w)//如果还没有动过
                   //权值大于0
            {dis[e[i].v]=dis[hh]+1;q[tail++]=e[i].v;}
            //比上一层多一    
        }
    }
    return dis[t]<inf;//如果返回1,dis【t】被更新还可以再做一遍
}//如果返回0 dis【t】=inf没有更新做完了
int dinic(int to,int f)
{
    if(to==t)return f;
    for(int i=current[to];i!=-1;i=e[i].next)
    {//current记录这个点当前已经遍历到的边的en值
    current[to]=i;
        if(dis[e[i].v]==dis[to]+1&&e[i].w)
        {//如果相连两点分在两个层次,权值大于0
            int d=dinic(e[i].v,min(e[i].w,f));
            if(d)
            {//正向边加了多少流量,反向边的容量加多少
                e[i].w-=d;
                e[i^1].w+=d;
                return d;
            }
        }
    }
    return 0;
}

void out()
{
    int ans=0;s=1;
    while(bfs())
    {//循环开始时 current等于first,是在后面循环中减少工作量
        for(int i=1;i<=t;i++)current[i]=first[i];
        int f=dinic(s,inf);
        if(f<=0){break;}
        ans+=f;
    }
   printf("%d\n",ans);

}
void input()
{
        int n,u,v,w;
    memset(first,-1,sizeof(first));
    scanf("%d%d",&n,&t);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        addedge(u,v,w,0);
    }
    out();
}
int main()
{
    input();
    return 0;
}

一脸懵逼,完全不知道该说些什么;

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值