hdu2435最大流最小割
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最大流最小割的更多相关文章
- hiho 第116周,最大流最小割定理,求最小割集S,T
小Hi:在上一周的Hiho一下中我们初步讲解了网络流的概念以及常规解法,小Ho你还记得内容么? 小Ho:我记得!网络流就是给定了一张图G=(V,E),以及源点s和汇点t.每一条边e(u,v)具有容量c ...
- hihocoder 网络流二·最大流最小割定理
网络流二·最大流最小割定理 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi:在上一周的Hiho一下中我们初步讲解了网络流的概念以及常规解法,小Ho你还记得内容么? ...
- [HihoCoder1378]网络流二·最大流最小割定理
思路: 根据最大流最小割定理可得最大流与最小割相等,所以可以先跑一遍EdmondsKarp算法.接下来要求的是经过最小割切割后的图中$S$所属的点集.本来的思路是用并查集处理所有前向边构成的残量网络, ...
- HDU 1569 方格取数(2)(最大流最小割の最大权独立集)
Description 给你一个m*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大. ...
- FZU 1844 Earthquake Damage(最大流最小割)
Problem Description Open Source Tools help earthquake researchers stay a step ahead. Many geological ...
- 【codevs1907】方格取数3(最大流最小割定理)
网址:http://codevs.cn/problem/1907/ 题意:在一个矩阵里选不相邻的若干个数,使这些数的和最大. 我们可以把它看成一个最小割,答案就是矩阵中的所有数-最小割.先把矩阵按国际 ...
- 紫书 例题 11-12 UVa 1515 (最大流最小割)
这道题要分隔草和洞, 然后刘汝佳就想到了"割"(不知道他怎么想的, 反正我没想到) 然后就按照这个思路走, 网络流建模然后求最大流最小割. 分成两部分, S和草连, 洞和T连 外围 ...
- HDU-4289-Control(最大流最小割,拆点)
链接: https://vjudge.net/problem/HDU-4289 题意: You, the head of Department of Security, recently receiv ...
- 牛客暑期第六场G /// 树形DP 最大流最小割定理
题目大意: 输入t,t个测试用例 每个测试用例输入n 接下来n行 输入u,v,w,树的无向边u点到v点权重为w 求任意两点间的最大流的总和 1.最大流最小割定理 即最大流等于最小割 2.无向树上的任意 ...
随机推荐
- docker的安装和基本的docker命令、镜像和容器的操作
1.yum 包更新到最新 yum update 2.安装需要的软件包, yum-util 提供yum-config-manager功能,另外两个是devicemapper驱动依赖的 yum insta ...
- ACM STU week3
STU ACM训练week3(2.5-2.15) By@Xiezeju 训练计划的CP4配套资源库 训练时间安排 定期任务 任务 每日 进行1小时的盲打训练锻练手速 打字网站,最好注册账号以保存进度 ...
- Java 多线程 02
多线程·线程间通信 和 GUI 单例设计模式 * A:单例设计模式 * 保证类在内存中只有一个对象 * B:如何保证 * a:控制类的创建,不让其他类来创建泵类的对象,私有化构造方法 * b:在本类中 ...
- PTA1071 - Speech Patterns - map计算不同单词个数
题意 输出给定字符串出现最多的字符串(小写输出)和出现次数. 所求字符串要求:字符中可以含有A-Z.0-9. 比如说题目给出的Can1,我们可以转换成can1,can1就算一个字符串整体,而不是单独的 ...
- web图像化服务管理工具
在 CentOS 8 中安装 Cockpit Web 控制台 Cockpit 是红帽开发的网页版图像化服务管理工具,优点是无需中间层,且可以管理多种服务. 根据其项目主站描述,Cockpit 有如下特 ...
- Azure Front Door(二)对后端 VM 进行负载均衡
一,引言 上一篇我们讲到通过 Azure Front Door 为我们的 Azure App Service 提供流量转发,而整个 Azure Front Door 在添加后端池的时候可选的后端类型是 ...
- 一些比较好的国外IT网站
1.在线编程练习: LintCode --在线刷题网站,阶梯式训练,可帮助你更快速深入地了解各类面试题型,提供专业导师写的最优代码作为参考 (Lintcode 标准答案查询--lintcode 的参考 ...
- Nodejs学习笔记(1) Nodejs安装+借助express模块简单部署服务器
1 安装 1.1 下载和安装 1.2 什么是REPL?如何使用? 1.3 npm对单一模块的安装和删除功能 1.4 通过package.json自定义模块(安装模块) 1.5 设置全局目录 2 部署网 ...
- 1.mysql读写
一.数据库读取(mysql) 参数 接受 作用 默认 sql or table_name string 读取的表名,或sql语句 无 con 数据库连接 数据库连接信息 无 index_col Int ...
- istio服务条目(ServiceEntry)介绍
使用服务条目资源(ServiceEntry)可以将条目添加到 Istio 内部维护的服务注册表中.添加服务条目后,Envoy 代理可以将流量发送到该服务,就好像该服务条目是网格中的服务一样.通过配置服 ...