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. three.js cannon.js物理引擎之约束(二)

    今天郭先生继续讲cannon.js的物理约束,之前的一篇文章曾简单的提及过PointToPointConstraint约束,那么今天详细的说一说cannon.js的约束和使用方法.在线案例请点击博客原 ...

  2. SQL学习笔记——创建数据库显示:文件激活错误,物理文件名不存在>>解决方案

    今天在创建数据库时,跟着老师一步一步的操作创建成功,但出于在厌恶冗长的数据库存储路径,于是,擅自更改了数据filename,让他保存在电脑桌面新建的文件夹,可是一执行就报错了. 老师源码: 1 cre ...

  3. react第三方库

    作者:慕课网链接:https://www.zhihu.com/question/59073695/answer/1071631250来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请 ...

  4. 【wp】2021V&NCTF

    前几天打完的V&NCTF公开赛,做题的时候没记过程,这是复现wp. 最后排名Top 18,三道RE+两道杂项(wp没啥可放的hhh)+一道web,感觉re题目还是挺好的,难度适中点赞,尤其pc ...

  5. 【数据库】Redis(2)--Redis的常用数据类型及命令

    1.Redis主要数据类型分类 Redis中存储数据常用的数据类型主要有五种:String.List.Set.Sorted Set.Hash,这五种数据结构在Redis中存储数据的命令掌握对于我们后期 ...

  6. 【linux】驱动-5-驱动框架分层分离&实战

    目录 前言 5. 分离分层 5.1 回顾-设备驱动实现 5.2 分离分层 5.3 设备 5.4 驱动 5.5 系统,模块 5.6 Makefile 参考: 前言 5. 分离分层 本章节记录实现LED驱 ...

  7. java例题_18 乒乓球比赛(对手问题)

    1 /*18 [程序 18 乒乓球赛] 2 题目:两个乒乓球队进行比赛,各出三人.甲队为 a,b,c 三人,乙队为 x,y,z 三人.已抽签决定比赛名单. 3 有人向队员打听比赛的名单.a说他不和 x ...

  8. java例题_02 101~200以内的素数

    1 /*2 [程序 2 输出素数] 2 题目:判断 101-200 之间有多少个素数,并输出所有素数. 3 程序分析:判断素数的方法:用一个数分别去除 2 到 sqrt(这个数),如果能被整除,则表明 ...

  9. 配置Java环境变量时的一个常见错误

    我们在把JDK路径配置为环境变量时,有一个常用的配置方法,就是把JDK根路径配置为"JAVA_HOME"值,然后在Path中添加一条"%JAVA_HOME%\bin&qu ...

  10. (数据科学学习手札115)Python+Dash快速web应用开发——交互表格篇(上)

    本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 这是我的系列教程Python+Dash快速web ...