POJ 1273 Drainage Ditches 题解与分析<网络流DINIC>

Drainage Ditches 草地排水

Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 49294 Accepted: 18658

 


描述

在农夫约翰的农场上,每逢下雨,Bessie最喜欢的三叶草地就积聚了一潭水。这意味着草地被水淹没了,并且小草要继续生长还要花相当长一段时间。因此,农夫约翰修建了一套排水系统来使贝茜的草地免除被大水淹没的烦恼(不用担心,雨水会流向附近的一条小溪)。作为一名一流的技师,农夫约翰已经在每条排水沟的一端安上了控制器,这样他可以控制流入排水沟的水流量。

农夫约翰知道每一条排水沟每分钟可以流过的水量,和排水系统的准确布局(起点为水潭而终点为小溪的一张网)。需要注意的是,有些时候从一处到另一处不只有一条排水沟。

根据这些信息,计算从水潭排水到小溪的最大流量。对于给出的每条排水沟,雨水只能沿着一个方向流动,注意可能会出现雨水环形流动的情形。

格式

PROGRAM NAME:ditch

INPUT FORMAT:

(file ditch.in)

第1行: 两个用空格分开的整数N (0 <= N <= 200) 和 M (2 <= M <= 200)。N是农夫John已经挖好的排水沟的数量,M是排水沟交叉点的数量。交点1是水潭,交点M是小溪。

第二行到第N+1行: 每行有三个整数,Si, Ei, 和 Ci。Si 和 Ei (1 <= Si, Ei <= M) 指明排水沟两端的交点,雨水从Si 流向Ei。Ci (0 <= Ci <= 10,000,000)是这条排水沟的最大容量。

OUTPUT FORMAT:

(file ditch.out)

输出一个整数,即排水的最大流量。

SAMPLE INPUT

5 4
1 2 40
1 4 20
2 4 20
2 3 30
3 4 10

SAMPLE OUTPUT

50

 

【分析】:用网络流的DINIC算法解。首先构图,读入x,y,z,将x到y的容量加上z,并记录x可以到y,y可以到x。接下来,构建层次图<用队列实现,先将1加入,每次取队头元素x,然后枚举与它有边连的点y,根据层次图性质,每次判断x到y是否有容量并且d[x]+1是否小于d[y],如果是就更新d[y]为d[x]+1,并将y加进队列,若队列中元素有M个,就说明建图完毕>,然后进行DINIC网络流算法,递归求增广路,只是更新的时候要判断是否初始点的d值+1等于到达点<此处就是DINIC算法对普通增广路算法的优化>

<提示:POJ1273与USACO 4.2.1相同,只是POJ1273是多组数据>

【代码】:

/*
    Problem: 1273  User: csyzcyj 
    Memory: 528K  Time: 16MS 
    Language: C++  Result: Accepted 
*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define MAX 201
#define IMAX 2147483647
struct LAKE{vector<long long> link;};
LAKE a[MAX];
long long N,M,map[MAX][MAX],ans=0,use;//map记录容量 
long long d[MAX];//d记录层次 
bool build()//构建层次图 
{
      long long q[MAX],tot=0;
      for(int i=0;i<=M+1;i++)
            d[i]=IMAX;
      q[++tot]=1;
      d[1]=0;
      for(int i=1;i<=tot;i++)
      {
            int now=q[i];
            for(int j=0;j<a[now].link.size();j++)
            {
                  int next=a[now].link[j];
                  if(map[now][next] && d[now]+1<d[next])
                  {
                        d[next]=d[now]+1;
                        q[++tot]=next;
                        if(tot==M)   return true;
                  }
            }
      }
      return false;
}
long long DINIC(long long now,long long flow)//flow为当前容量最小值 
{
      long long new1;
      if(flow==0)  return 0;//没有可用容量 
      if(now==M)   return flow;//如果到达了汇点 
      for(int i=0;i<a[now].link.size();i++)
      {
            long long next=a[now].link[i];
            if(d[now]+1==d[next] && (new1=DINIC(next,min(flow,map[now][next]))))
            {
                  map[now][next]-=new1;
                  map[next][now]+=new1;//其反向弧加上正向弧减去的流量 
                  return new1;
            }
      }
      return 0;
}
int main()
{     
      while(scanf("%lld%lld",&N,&M)!=EOF)
      {
	       memset(map,0,sizeof(map));
	       memset(a,0,sizeof(a));
	       memset(d,0,sizeof(d));
	       ans=0;
	       for(int i=1;i<=N;i++)
	       {
                 long long A,B,C;
                 scanf("%lld%lld%lld",&A,&B,&C);
                 map[A][B]+=C;
                 a[A].link.push_back(B);
                 a[B].link.push_back(A);
           }
           while(build())
           {
                 while(use=DINIC(1,IMAX))
                 {
                       ans+=use;
                 }
           }
           printf("%lld\n",ans);
      }
	  //system("pause");
      return 0;
}

转载注明出处:http://blog.csdn.net/u011400953

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
POJ 3635 是一道比较经典的数学题目,主要考察了一些数学知识和算法。下面是这道题的 Java 解题思路和代码实现: 题目描述: 给定一个正整数N,求最小的正整数M,使得 N*M 的十进制表示中只包含数字0和1。 输入格式: 一个正整数N。 输出格式: 一个正整数M,表示满足条件的最小正整数M。 Java 代码实现: ```java import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); long n = sc.nextLong(); long res = 1; Queue<Long> queue = new LinkedList<>(); Set<Long> set = new HashSet<>(); queue.offer(1L); set.add(1L); while (!queue.isEmpty()) { long t = queue.poll(); if (t % n == 0) { res = t; break; } long a = (t * 10) % n; long b = (t * 10 + 1) % n; if (!set.contains(a)) { queue.offer(a); set.add(a); } if (!set.contains(b)) { queue.offer(b); set.add(b); } } System.out.println(res); } } ``` 思路解析: 这道题的解题思路比较巧妙,我们可以采用 BFS 算法来解决。我们可以从 1 开始进行 BFS,每次将当前的数乘以 10 或者乘以 10 再加上 1,得到两个新的数,然后判断这两个新的数是否是 n 的倍数,如果是,则找到了最小的满足条件的数,退出 BFS。如果不是,则将两个新的数加入队列,继续进行 BFS。需要注意的是,由于 N 可能非常大,所以我们需要使用 long 类型来存储数值,同时我们需要使用集合来避免重复计算。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值