题面

UPD:COGS 貌似进不去了,链接失效就删掉了。

如果你不小心看到了题目评论区,那你就会知道这是一道双倍经验题,另一题的链接见题目评论区……

网络流+tarjan好题,但如果你真的的理解了网络流反向边的作用,那这就是一道大水题……

题目要求出一定在最大流中的边的数目,显然先跑网络流(废话),然后考虑到题目要求的是一定在最大流中的边,换就话说,这条边要不可替代,什么边不可替代呢——割边(大雾)连接着两个强连通分量的边。

为什么呢?

首先,我们要知道边满流的概念。对于正向边(并没有找到标准说法,若有知道的,评论告知),当且仅当他的流量等于容量(废话),在这道题中,就是一条匹配边(容量为一);对于反向边,当且仅当他对应的正向边流量为零,在这道题中,就是一条未匹配边的反向边。(也许和标准定义不一样,就先这么理解这道题吧)

若一条边在某个强连通分量中,则这条边连接的两个点X—>Y,一定存在一条路径Y—>X,且这条路径上的边全部都是反向边,故原图中必然存在一条路径从X—>Y,且路径上的边全部都是未匹配边,即这条边不是不可替代的。

于是,我们就可以在满流的边上跑tarjan,然后枚举每一条满流的判断即可。

 #include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <complex>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define rg register
#define ll long long
using namespace std; inline int gi()
{
rg int r = ; rg bool b = ; rg char c = getchar();
while ((c < '' || c > '') && c != '-') c = getchar();
if (c == '-') b = ;
while (c >= '' && c <= '') { r = (r << ) + (r << ) + c - '', c = getchar(); }
if (b) return r; return -r;
} const int inf = , N = 1e5+, M = 6e5+;
int n,m,w,S,T,Time,num,mac[N],pre[N],f[N];
int stc[N],scc[N],dep[N],dfn[N],low[N];
queue <int> q;
struct Edge
{
int to,nx,cap;
}eg[M]; inline void add(int x,int y,int z)
{
eg[++num]=(Edge){y,f[x],z}; f[x]=num;
} inline int dfs(int o,int flow)
{
if (!flow || o == T)
return flow;
int i,to,cap,tmp,fl;
fl=;
for (i=f[o]; i; i=eg[i].nx)
{
to=eg[i].to, cap=eg[i].cap;
if (dep[to] != dep[o]+ || cap <= )
continue;
tmp=dfs(to,min(flow,cap));
eg[i].cap-=tmp, eg[i^].cap+=tmp;
fl+=tmp, flow-=tmp;
if (!flow)
break;
}
if (!fl)
dep[o]=;
return fl;
} inline int bfs()
{
int i,o,to,cap;
memset(dep,,sizeof(dep));
q.push(S), dep[S]=;
while (!q.empty())
{
o=q.front(), q.pop();
for (i=f[o]; i; i=eg[i].nx)
{
to=eg[i].to, cap=eg[i].cap;
if (dep[to] || cap <= )
continue;
dep[to]=dep[o]+;
if (to == T)
{
while (!q.empty()) q.pop();
break;
}
q.push(to);
}
}
return dep[T];
} inline int dinic()
{
int flow;
flow=;
while (bfs())
flow+=dfs(S,inf);
return flow;
} inline void tarjan(int o)
{
int i,to,cap;
dfn[o]=low[o]=++Time;
stc[++stc[]]=o;
for (i=f[o]; i; i=eg[i].nx)
{
to=eg[i].to, cap=eg[i].cap;
if (cap > )
continue;
if (!dfn[to])
{
tarjan(to);
low[o]=min(low[to],low[o]);
}
else if (!scc[to])
low[o]=min(low[o],dfn[to]);
}
if (low[o] == dfn[o])
{
++scc[T+];
do
{
to=stc[stc[]--];
scc[to]=scc[T+];
}
while (to != o);
}
} int main()
{
freopen("sphere.in","r",stdin);
freopen("sphere.out","w",stdout);
int i,x,y,ans,cap;
n=gi(), m=gi();
S=, T=n+, num=, ans=, n>>=;
for (i=; i<=m; i++)
{
x=gi(), y=gi();
add(x,y,), add(y,x,);
}
for (i=; i<=n; ++i)
{
add(S,i,), add(i,S,);
add(i+n,T,), add(T,i+n,);
}
w=dinic();
for (i=S; i<=T; ++i)
if (!dfn[i])
tarjan(i);
m<<=, m++;
for (i=; i<=m; i+=)
{
cap=eg[i].cap, x=eg[i].to, y=eg[i^].to;
if (cap > )
continue;
if (scc[x] != scc[y])
ans++;
}
printf("%d\n",ans);
return ;
}

最新文章

  1. Linux.NET学习手记(7)
  2. See you~_树状数组
  3. 导出excel失败,提醒提示加载类型库/DDL出错
  4. ECMAScript 6学习笔记(二):let和块级作用域
  5. NSMutableString
  6. white-space:nowrap 的妙用
  7. __nonnull 和 __nullable (Swift 和 Objective-C混编)
  8. SVN服务器使用(一)
  9. phpcms源码解析(2)
  10. PHP 之mysql空字符串问题
  11. cocos2dx 3.0 学习笔记 引用cocostudio库 的环境配置
  12. linux启动httpd服务出现 Could not reliably determine the server`s fully qualified domain name.
  13. 调用 LoadLibraryEx 失败,在 ISAPI 筛选器 &quot;C:\Windows\Microsoft.NET\Framework\v4.0.30319\\aspnet_filter.dll&quot; 上
  14. Some Websites To Learning Laravel
  15. as 插件GsonFormat用法(json字符串快速生成javabean)
  16. 错误票据|2013年蓝桥杯B组题解析第七题-fishers
  17. 【Ruby】【基础】
  18. NYOJ 737:石子合并(一)(区间dp)
  19. Microsoft.Office.Core 引用以及 Microsoft.Office.Core.MsoTriState 的问题
  20. RocketMQ入门(简介、特点)

热门文章

  1. kafka技术分享02--------kafka入门
  2. go语言:函数参数传递详解
  3. n个平面把空间最多分成几个部分?
  4. Android Studio apk 打包流程(转)http://blog.chinaunix.net/uid-26000296-id-5567890.html
  5. 3.环境搭建-Hadoop(CDH)集群搭建
  6. powerDesignner连接数据库
  7. 【java读书笔记】——java的异常处理
  8. scp windows 和 linux 远程复制 (双向)
  9. [转]eclipse查看某个java类属于哪个jar包
  10. 2016最新手机号码正则、身份证JS正则表达式