洛谷【模板】网络最大流JAVA实现

运用EK算法轻松解决模板问题(只会模板qwq)!

前提会的算法:广度优先搜索 ,数据结构我用的是链式前向星存边;

推荐播客:(前向星)https://blog.csdn.net/ZHangFFYY/article/details/77871897

(网络流)http://www.sohu.com/a/243746046_100201031

(Dininc算法)https://www.cnblogs.com/SYCstudio/p/7260613.html

对于正向边和反向边的存储识别,应为是一起连续存的,正向边的编号为偶数,对应的反向边为奇数

更新路径:对该路径上每条边的正反向边都更新;

注意:在本文中开始初始存的权值定义是该边(正向)还能流多少量,在找到一条增广路,对该路径更新时,无论正反边权值都减去更新值,如果是正边,则对应的反边跟着加上更新值(可以后悔的多了),如果是反边,则对应的正边加上更新值(后悔成功)。

还是老地方,会卡我时间用JAVA,不得不套用大佬的快读模板;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
import java.util.StringTokenizer;

public class Main {
	public static class node{   //存边
		private int to;
		private int next;
		private int v;
		
	public node(){
		
	} 	
	}
	public static class pre{  //记录路径
		private int e;       //该边的编号
		private int b;        //该边的去向
		public pre(){
			
		}
		public pre(int b,int e){
			this.b=b;
			this.e=e;
		}
	}
	
	static int cnt=0,head[];
	static node a[];
	static pre pre[];
	static boolean vis[];
	static int n,m,s,t;
  public static void main(String[] args) {
       FastScanner fs = new FastScanner();
	n=fs.nextInt();        //源点总数
	m=fs.nextInt();        //边的数量
    s =fs.nextInt();       //起点
	t=fs.nextInt();        //终点
	a=new node[2*(m+1)];
	head=new int[n+1];
	for (int i = 0; i <=n; i++) {  
		head[i]=-1;
	}
	for (int i = 0; i <m; i++) {  //存数据
		int x=fs.nextInt();
		int y=fs.nextInt();
		int v=fs.nextInt();
		add(x,y,v);
		add(y,x,0);
	}
	System.out.println(ek());
	
}
  public static void add(int x,int y,int v){ //前向星存
	  a[cnt]=new node();
	  a[cnt].to=y;         
	  a[cnt].v=v;
	  a[cnt].next=head[x];
	  head[x]=cnt++;
  }
  public static boolean bfs(){     //寻找是否有增广路
	  vis=new boolean[n+1];         //标记访问,防止重复访问
	  pre=new pre[n+1];               //初始化记录路径
	  Queue<Integer> d=new LinkedList();
	  vis[s]=true;
	  d.offer(s);
	  while(!d.isEmpty()){
		  int v=d.poll();
		  for(int u=head[v];;u=a[u].next){ //搜寻该点所有的边
			  if(u==-1)break;         //到头了就结束
			  int f=a[u].to;          
			  if(!vis[f]&&a[u].v>0){         //查看是否访问和是否为可行流
				  vis[f]=true;
				  pre[f]=new pre(v,u);      //标记路径,后面好更新
				  if(f==t)return true;
				  d.offer(f);
			  }
		  }
	  }
	  return false;
  }
  public static int ek(){
	  int ans=0;
	  while(bfs()){
		  int min=Integer.MAX_VALUE;
		  for (int i =t; i!=s; i=pre[i].b) { //寻找这条路可流入量
				min=Math.min(min,a[pre[i].e].v);
		}
		  for (int i =t; i!=s; i=pre[i].b) {  //更新
			if(pre[i].e%2!=0){           //该边减,对应的相反边加
				a[pre[i].e].v-=min;
				a[pre[i].e-1].v+=min;
			}else{
				a[pre[i].e].v-=min;
				a[pre[i].e+1].v+=min;
			}
		}
		  ans+=min;               //流入量
	  }
	 return ans; 
  }
  public static class FastScanner {
      private BufferedReader br;
      private StringTokenizer st;
      public FastScanner() {
          br = new BufferedReader(new InputStreamReader(System.in));
      }

      public String nextToken() {
          while(st == null || !st.hasMoreElements()) {
              try {
                  st = new StringTokenizer(br.readLine());
              } catch (IOException e) {
                  // TODO Auto-generated catch block
                  e.printStackTrace();
              }
          }
          return st.nextToken();
      }

      public int nextInt() {
          return Integer.valueOf(nextToken());
      }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值