2435  There is a war

题意:

      给你一个有向图,其中可以有一条边是无敌的,这条边可以是图中的边,也可以是自己任意加上去的图中没有的边,这条无敌的边不可以摧毁,让1和n无法连通的最大摧毁费用,就是1到n的最小割中的最大的那个,这个题卡了好几天,一开始是各种方法各种wa,后来无意中发现自己犯了个sb错误,结果改正后以前的各种方法各种ac,比赛要是碰到这样的事估计就跪了...

思路:

     首先能确定的就是题目要求咱们就最小割(最大流 = 最小割),但关键是有那么一条无坚不摧的nb道路,所以一开始的想法肯定是暴力枚举N*N的边,直接TLE出翔了,那么就优化,记得以前的一道题目 给你一个图求删除其中一条边最短路中最大的那个,答案是只枚举最短路上的边就可以了, 这个题目也是类似,只要枚举最小割后两个集合的点组成的边就行了,因为假如点a和点b是一个集合的,那么把边ab变成无敌的没有意思,最小割的值不会改变,,那么怎么吧分成两个集合呢,两种方法,一个是深搜,这个方法容易理解,先跑一遍最大流,然后从点1开始深搜,如果当前点走过或者没有流量了(跑完一遍最大流后的流量),直接continue,这样被mark的点就是左集合的点,剩下的就是右集合的点,还有一种方法就是直接看DINIC后的deep数组,如果不等于-1就是左集合的,否则的就是右集合的,这个我结论是网上的,我还不知道为什么,分成两个集合后就可以枚举两个集合的点建枚举的边了,这块也有两个方法,一个就是之前不是跑一边最大流了吗,加上当前枚举边,直接在残余网络上跑,取得最大的max最后输出一开始那个最大流maxflow+max,(记得每次跑之前都还原成第一次跑完的残余网路),第二种方法就是直接重新建边,一开始的时候吧m条边记录下来,每次枚举都重新建图,然后加上枚举的边跑,最后输出的是最大流中最大的那个maxflow.下面是三种方法的代码..

深搜找源集和汇集,在残余网络上跑 15ms AC

#include<stdio.h>

#include<string.h>

#include<queue>


#define N_node 120

#define N_edge 22000

#define inf 1000000000


using namespace std;


typedef struct

{

   int to ,next ,cost;

}STAR;

typedef struct

{

   int x ,t;

}DEP;

STAR E[N_edge] ,E_[N_edge];

DEP xin ,tou;

int list[N_node] ,list1[N_node] ,tot;

int list2[N_node];

int deep[N_node];

int mks[N_node] ,mks_;

int mkh[N_node] ,mkh_;

int mark[N_node];

void add(int a ,int b ,int c)

{

   E[++tot].to = b;

   E[tot].cost = c;

   E[tot].next = list[a];

   list[a] = tot;

   

   E[++tot].to = a;

   E[tot].cost = 0;

   E[tot].next = list[b];

   list[b] = tot;

}

int minn(int a ,int b)

{

   return a < b ? a : b;

}

bool BFS_DEEP(int s ,int t ,int n)

{

    memset(deep ,255 ,sizeof(deep));

    deep[s] = 0;

    xin.x = s;

    xin.t = 0;

    queue<DEP>q;

    q.push(xin);

    while(!q.empty())

    {

      tou = q.front();

      q.pop();

      for(int k = list[tou.x] ;k ;k = E[k].next)

      {

         xin.x = E[k].to;

         xin.t = tou.t + 1;

         if(deep[xin.x] != -1 || !E[k].cost)

         continue;

         deep[xin.x] = xin.t;

         q.push(xin);

      }

   }

   for(int i = 0 ;i <= n ;i ++)

   list1[i] = list[i];

   return deep[t] != -1;

}

int DFS_MAX_FLOW(int s ,int t ,int flow)

{

   if(s == t) return flow;

   int nowflow = 0;

   for(int k = list1[s] ;k ;k = E[k].next)

   {

      list1[s] = k;

      int to = E[k].to;

      int c = E[k].cost;

      if(deep[to] != deep[s] + 1||!E[k].cost)

      continue;

      int tmp = DFS_MAX_FLOW(to ,t ,minn(c ,flow - nowflow));

      nowflow += tmp;

      E[k].cost -= tmp;

      E[k^1].cost += tmp;

      if(nowflow == flow)

      break;

   }

   if(!nowflow)

   deep[s] = 0;

   return nowflow;

}

int DINIC(int s ,int t ,int n)

{

   int ans = 0;

   while(BFS_DEEP(s ,t ,n))

   {

      ans += DFS_MAX_FLOW(s ,t ,inf);

   }

   return ans;

}

void DFS(int s)

{

   for(int k = list[s] ;k ;k = E[k].next)

   {

      int to = E[k].to;

      if(mark[to] || !E[k].cost)

      continue;

      mark[to] = 1;

      DFS(to);

   }

   return ;

}

int main ()

{

   int n ,m ,i ,j ,t;

   int a ,b ,c;

   scanf("%d" ,&t);

   while(t--)

   {

      memset(list ,0 ,sizeof(list));

      tot = 1;

      scanf("%d %d" ,&n ,&m);

      for(i = 1 ;i <= m ;i ++)

      {

         scanf("%d %d %d" ,&a ,&b ,&c);

         add(a ,b ,c);

      }

      int ans = DINIC(1 ,n ,n);

      mks_ = mkh_ = 0;

      memset(mark ,0 ,sizeof(mark));

      mark[1] = 1;

      DFS(1);

      for(i = 2 ;i < n ;i ++)

      if(mark[i]) mks[++mks_] = i;

      else mkh[++mkh_] = i;

      

      for(i = 1 ;i <= tot ;i ++)

      E_[i] = E[i];

      int mktot = tot;

      for(i = 1 ;i <= n ;i ++)

      list2[i] = list[i];

      

      int max = 0;

      for(i = 1 ;i <= mks_ ;i ++)

      for(j = 1 ;j <= mkh_ ;j ++)

      {

         a = mks[i] ,b = mkh[j];

         for(int k = 1 ;k <= mktot ;k ++)

         E[k] = E_[k];

         memset(list ,0 ,sizeof(list));

         for(int k = 1 ;k <= n ;k ++)

         list[k] = list2[k];

         tot = mktot;

         add(a ,b ,inf);

         int tmp = DINIC(1 ,n ,n);

         if(max < tmp) max = tmp;

      }

      printf("%d\n" ,ans + max);

   }

   return 0;

}

         

         

      

      

根据deep数组找源集和汇集,在残余网络上跑 31ms AC

#include<stdio.h>

#include<string.h>

#include<queue>

#define N_node 120

#define N_edge 22000

#define inf 1000000000

using namespace std;

typedef struct

{

   int to ,next ,cost;

}STAR;

typedef struct

{

   int x ,t;

}DEP;

STAR E[N_edge] ,E_[N_edge];

DEP xin ,tou;

int list[N_node] ,list1[N_node] ,tot;

int list2[N_node];

int deep[N_node];

int mks[N_node] ,mks_;

int mkh[N_node] ,mkh_;

void add(int a ,int b ,int c)

{

   E[++tot].to = b;

   E[tot].cost = c;

   E[tot].next = list[a];

   list[a] = tot;

   

   E[++tot].to = a;

   E[tot].cost = 0;

   E[tot].next = list[b];

   list[b] = tot;

}

int minn(int a ,int b)

{

   return a < b ? a : b;

}

bool BFS_DEEP(int s ,int t ,int n)

{

    memset(deep ,255 ,sizeof(deep));

    deep[s] = 0;

    xin.x = s;

    xin.t = 0;

    queue<DEP>q;

    q.push(xin);

    while(!q.empty())

    {

      tou = q.front();

      q.pop();

      for(int k = list[tou.x] ;k ;k = E[k].next)

      {

         xin.x = E[k].to;

         xin.t = tou.t + 1;

         if(deep[xin.x] != -1 || !E[k].cost)

         continue;

         deep[xin.x] = xin.t;

         q.push(xin);

      }

   }

   for(int i = 0 ;i <= n ;i ++)

   list1[i] = list[i];

   return deep[t] != -1;

}

int DFS_MAX_FLOW(int s ,int t ,int flow)

{

   if(s == t) return flow;

   int nowflow = 0;

   for(int k = list1[s] ;k ;k = E[k].next)

   {

      list1[s] = k;

      int to = E[k].to;

      int c = E[k].cost;

      if(deep[to] != deep[s] + 1||!E[k].cost)

      continue;

      int tmp = DFS_MAX_FLOW(to ,t ,minn(c ,flow - nowflow));

      nowflow += tmp;

      E[k].cost -= tmp;

      E[k^1].cost += tmp;

      if(nowflow == flow)

      break;

   }

   if(!nowflow)

   deep[s] = 0;

   return nowflow;

}

int DINIC(int s ,int t ,int n)

{

   int ans = 0;

   while(BFS_DEEP(s ,t ,n))

   {

      ans += DFS_MAX_FLOW(s ,t ,inf);

   }

   return ans;

}

int main ()

{

   int n ,m ,i ,j ,t;

   int a ,b ,c;

   scanf("%d" ,&t);

   while(t--)

   {

      memset(list ,0 ,sizeof(list));

      tot = 1;

      scanf("%d %d" ,&n ,&m);

      for(i = 1 ;i <= m ;i ++)

      {

         scanf("%d %d %d" ,&a ,&b ,&c);

         add(a ,b ,c);

      }

      int ans = DINIC(1 ,n ,n);

      mks_ = mkh_ = 0;

      for(i = 2 ;i < n ;i ++)

      if(deep[i] != -1) mks[++mks_] = i;

      else mkh[++mkh_] = i;

      

      for(i = 1 ;i <= tot ;i ++)

      E_[i] = E[i];

      int mktot = tot;

      for(i = 1 ;i <= n ;i ++)

      list2[i] = list[i];

      

      int max = 0;

      for(i = 1 ;i <= mks_ ;i ++)

      for(j = 1 ;j <= mkh_ ;j ++)

      {

         a = mks[i] ,b = mkh[j];

         for(int k = 1 ;k <= mktot ;k ++)

         E[k] = E_[k];

         memset(list ,0 ,sizeof(list));

         for(int k = 1 ;k <= n ;k ++)

         list[k] = list2[k];

         tot = mktot;

         add(a ,b ,inf);

         int tmp = DINIC(1 ,n ,n);

         if(max < tmp) max = tmp;

      }

      printf("%d\n" ,ans + max);

   }

   return 0;

}

         
直接重新建图,深搜找源集和汇集(容易理解) 15msAC


#include<stdio.h>

#include<string.h>

#include<queue>

#define N_node 120

#define N_edge 22000

#define inf 1000000000

using namespace std;

typedef struct

{

   int to ,next ,cost;

}STAR;

typedef struct

{

   int x ,t;

}DEP;

typedef struct

{

   int a ,b ,c;

}EDGE;

STAR E[N_edge];

EDGE edge[N_edge];

DEP xin ,tou;

int list[N_node] ,list1[N_node] ,tot;

int deep[N_node];

int mks[N_node] ,mks_;

int mkh[N_node] ,mkh_;

int mark[N_node];

void add(int a ,int b ,int c)

{

   E[++tot].to = b;

   E[tot].cost = c;

   E[tot].next = list[a];

   list[a] = tot;

   

   E[++tot].to = a;

   E[tot].cost = 0;

   E[tot].next = list[b];

   list[b] = tot;

}

int minn(int a ,int b)

{

   return a < b ? a : b;

}

bool BFS_DEEP(int s ,int t ,int n)

{

    memset(deep ,255 ,sizeof(deep));

    deep[s] = 0;

    xin.x = s;

    xin.t = 0;

    queue<DEP>q;

    q.push(xin);

    while(!q.empty())

    {

      tou = q.front();

      q.pop();

      for(int k = list[tou.x] ;k ;k = E[k].next)

      {

         xin.x = E[k].to;

         xin.t = tou.t + 1;

         if(deep[xin.x] != -1 || !E[k].cost)

         continue;

         deep[xin.x] = xin.t;

         q.push(xin);

      }

   }

   for(int i = 0 ;i <= n ;i ++)

   list1[i] = list[i];

   return deep[t] != -1;

}

int DFS_MAX_FLOW(int s ,int t ,int flow)

{

   if(s == t) return flow;

   int nowflow = 0;

   for(int k = list1[s] ;k ;k = E[k].next)

   {

      list1[s] = k;

      int to = E[k].to;

      int c = E[k].cost;

      if(deep[to] != deep[s] + 1||!E[k].cost)

      continue;

      int tmp = DFS_MAX_FLOW(to ,t ,minn(c ,flow - nowflow));

      nowflow += tmp;

      E[k].cost -= tmp;

      E[k^1].cost += tmp;

      if(nowflow == flow)

      break;

   }

   if(!nowflow)

   deep[s] = 0;

   return nowflow;

}

int DINIC(int s ,int t ,int n)

{

   int ans = 0;

   while(BFS_DEEP(s ,t ,n))

   {

      ans += DFS_MAX_FLOW(s ,t ,inf);

   }

   return ans;

}

void DFS(int s)

{

   for(int k = list[s] ;k ;k = E[k].next)

   {

      int to = E[k].to;

      if(mark[to] || !E[k].cost)

      continue;

      mark[to] = 1;

      DFS(to);

   }

   return ;

}

int main ()

{

   int n ,m ,i ,j ,t;

   int a ,b ,c;

   scanf("%d" ,&t);

   while(t--)

   {

      memset(list ,0 ,sizeof(list));

      tot = 1;

      scanf("%d %d" ,&n ,&m);

      for(i = 1 ;i <= m ;i ++)

      {

         scanf("%d %d %d" ,&a ,&b ,&c);

         add(a ,b ,c);

         edge[i].a = a ,edge[i].b = b ,edge[i].c = c;

      }

      int ans = DINIC(1 ,n ,n);

      mks_ = mkh_ = 0;

      memset(mark ,0 ,sizeof(mark));

      mark[1] = 1;

      DFS(1);

      for(i = 2 ;i < n ;i ++)

      if(mark[i]) mks[++mks_] = i;

      else mkh[++mkh_] = i;

      for(i = 1 ;i <= mks_ ;i ++)

      for(j = 1 ;j <= mkh_ ;j ++)

      {

         a = mks[i] ,b = mkh[j];

         memset(list ,0 ,sizeof(list));

         tot = 1;

         for(int k = 1 ;k <= m ;k ++)

         add(edge[k].a ,edge[k].b ,edge[k].c);

         add(a ,b ,inf);

         int tmp = DINIC(1 ,n ,n);

         if(ans < tmp) ans = tmp;

      }

      printf("%d\n" ,ans);

   }

   return 0;

}

												

hdu2435最大流最小割的更多相关文章

  1. hiho 第116周,最大流最小割定理,求最小割集S,T

    小Hi:在上一周的Hiho一下中我们初步讲解了网络流的概念以及常规解法,小Ho你还记得内容么? 小Ho:我记得!网络流就是给定了一张图G=(V,E),以及源点s和汇点t.每一条边e(u,v)具有容量c ...

  2. hihocoder 网络流二·最大流最小割定理

    网络流二·最大流最小割定理 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi:在上一周的Hiho一下中我们初步讲解了网络流的概念以及常规解法,小Ho你还记得内容么? ...

  3. [HihoCoder1378]网络流二·最大流最小割定理

    思路: 根据最大流最小割定理可得最大流与最小割相等,所以可以先跑一遍EdmondsKarp算法.接下来要求的是经过最小割切割后的图中$S$所属的点集.本来的思路是用并查集处理所有前向边构成的残量网络, ...

  4. HDU 1569 方格取数(2)(最大流最小割の最大权独立集)

    Description 给你一个m*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大.   ...

  5. FZU 1844 Earthquake Damage(最大流最小割)

    Problem Description Open Source Tools help earthquake researchers stay a step ahead. Many geological ...

  6. 【codevs1907】方格取数3(最大流最小割定理)

    网址:http://codevs.cn/problem/1907/ 题意:在一个矩阵里选不相邻的若干个数,使这些数的和最大. 我们可以把它看成一个最小割,答案就是矩阵中的所有数-最小割.先把矩阵按国际 ...

  7. 紫书 例题 11-12 UVa 1515 (最大流最小割)

    这道题要分隔草和洞, 然后刘汝佳就想到了"割"(不知道他怎么想的, 反正我没想到) 然后就按照这个思路走, 网络流建模然后求最大流最小割. 分成两部分, S和草连, 洞和T连 外围 ...

  8. HDU-4289-Control(最大流最小割,拆点)

    链接: https://vjudge.net/problem/HDU-4289 题意: You, the head of Department of Security, recently receiv ...

  9. 牛客暑期第六场G /// 树形DP 最大流最小割定理

    题目大意: 输入t,t个测试用例 每个测试用例输入n 接下来n行 输入u,v,w,树的无向边u点到v点权重为w 求任意两点间的最大流的总和 1.最大流最小割定理 即最大流等于最小割 2.无向树上的任意 ...

随机推荐

  1. docker的安装和基本的docker命令、镜像和容器的操作

    1.yum 包更新到最新 yum update 2.安装需要的软件包, yum-util 提供yum-config-manager功能,另外两个是devicemapper驱动依赖的 yum insta ...

  2. ACM STU week3

    STU ACM训练week3(2.5-2.15) By@Xiezeju 训练计划的CP4配套资源库 训练时间安排 定期任务 任务 每日 进行1小时的盲打训练锻练手速 打字网站,最好注册账号以保存进度 ...

  3. Java 多线程 02

    多线程·线程间通信 和 GUI 单例设计模式 * A:单例设计模式 * 保证类在内存中只有一个对象 * B:如何保证 * a:控制类的创建,不让其他类来创建泵类的对象,私有化构造方法 * b:在本类中 ...

  4. PTA1071 - Speech Patterns - map计算不同单词个数

    题意 输出给定字符串出现最多的字符串(小写输出)和出现次数. 所求字符串要求:字符中可以含有A-Z.0-9. 比如说题目给出的Can1,我们可以转换成can1,can1就算一个字符串整体,而不是单独的 ...

  5. web图像化服务管理工具

    在 CentOS 8 中安装 Cockpit Web 控制台 Cockpit 是红帽开发的网页版图像化服务管理工具,优点是无需中间层,且可以管理多种服务. 根据其项目主站描述,Cockpit 有如下特 ...

  6. Azure Front Door(二)对后端 VM 进行负载均衡

    一,引言 上一篇我们讲到通过 Azure Front Door 为我们的 Azure App Service 提供流量转发,而整个 Azure Front Door 在添加后端池的时候可选的后端类型是 ...

  7. 一些比较好的国外IT网站

    1.在线编程练习: LintCode --在线刷题网站,阶梯式训练,可帮助你更快速深入地了解各类面试题型,提供专业导师写的最优代码作为参考 (Lintcode 标准答案查询--lintcode 的参考 ...

  8. Nodejs学习笔记(1) Nodejs安装+借助express模块简单部署服务器

    1 安装 1.1 下载和安装 1.2 什么是REPL?如何使用? 1.3 npm对单一模块的安装和删除功能 1.4 通过package.json自定义模块(安装模块) 1.5 设置全局目录 2 部署网 ...

  9. 1.mysql读写

    一.数据库读取(mysql) 参数 接受 作用 默认 sql or table_name string 读取的表名,或sql语句 无 con 数据库连接 数据库连接信息 无 index_col Int ...

  10. istio服务条目(ServiceEntry)介绍

    使用服务条目资源(ServiceEntry)可以将条目添加到 Istio 内部维护的服务注册表中.添加服务条目后,Envoy 代理可以将流量发送到该服务,就好像该服务条目是网格中的服务一样.通过配置服 ...