题面
UPD:COGS 貌似进不去了,链接失效就删掉了。
如果你不小心看到了题目评论区,那你就会知道这是一道双倍经验题,另一题的链接见题目评论区……
网络流+tarjan好题,但如果你真的的理解了网络流反向边的作用,那这就是一道大水题……
题目要求出一定在最大流中的边的数目,显然先跑网络流(废话),然后考虑到题目要求的是一定在最大流中的边,换就话说,这条边要不可替代,什么边不可替代呢——割边(大雾)连接着两个强连通分量的边。
为什么呢?
首先,我们要知道边满流的概念。对于正向边(并没有找到标准说法,若有知道的,评论告知),当且仅当他的流量等于容量(废话),在这道题中,就是一条匹配边(容量为一);对于反向边,当且仅当他对应的正向边流量为零,在这道题中,就是一条未匹配边的反向边。(也许和标准定义不一样,就先这么理解这道题吧)
若一条边在某个强连通分量中,则这条边连接的两个点X—>Y,一定存在一条路径Y—>X,且这条路径上的边全部都是反向边,故原图中必然存在一条路径从X—>Y,且路径上的边全部都是未匹配边,即这条边不是不可替代的。
于是,我们就可以在满流的边上跑tarjan,然后枚举每一条满流的判断即可。
1 #include <map> 2 #include <set> 3 #include <cmath> 4 #include <queue> 5 #include <stack> 6 #include <cstdio> 7 #include <string> 8 #include <vector> 9 #include <cstring> 10 #include <complex> 11 #include <cstdlib> 12 #include <iostream> 13 #include <algorithm> 14 #define rg register 15 #define ll long long 16 using namespace std; 17 18 inline int gi() 19 { 20 rg int r = 0; rg bool b = 1; rg char c = getchar(); 21 while ((c < '0' || c > '9') && c != '-') c = getchar(); 22 if (c == '-') b = 0; 23 while (c >= '0' && c <= '9') { r = (r << 1) + (r << 3) + c - '0', c = getchar(); } 24 if (b) return r; return -r; 25 } 26 27 const int inf = 240002357, N = 1e5+5, M = 6e5+5; 28 int n,m,w,S,T,Time,num,mac[N],pre[N],f[N]; 29 int stc[N],scc[N],dep[N],dfn[N],low[N]; 30 queue <int> q; 31 struct Edge 32 { 33 int to,nx,cap; 34 }eg[M]; 35 36 inline void add(int x,int y,int z) 37 { 38 eg[++num]=(Edge){y,f[x],z}; f[x]=num; 39 } 40 41 inline int dfs(int o,int flow) 42 { 43 if (!flow || o == T) 44 return flow; 45 int i,to,cap,tmp,fl; 46 fl=0; 47 for (i=f[o]; i; i=eg[i].nx) 48 { 49 to=eg[i].to, cap=eg[i].cap; 50 if (dep[to] != dep[o]+1 || cap <= 0) 51 continue; 52 tmp=dfs(to,min(flow,cap)); 53 eg[i].cap-=tmp, eg[i^1].cap+=tmp; 54 fl+=tmp, flow-=tmp; 55 if (!flow) 56 break; 57 } 58 if (!fl) 59 dep[o]=0; 60 return fl; 61 } 62 63 inline int bfs() 64 { 65 int i,o,to,cap; 66 memset(dep,0,sizeof(dep)); 67 q.push(S), dep[S]=1; 68 while (!q.empty()) 69 { 70 o=q.front(), q.pop(); 71 for (i=f[o]; i; i=eg[i].nx) 72 { 73 to=eg[i].to, cap=eg[i].cap; 74 if (dep[to] || cap <= 0) 75 continue; 76 dep[to]=dep[o]+1; 77 if (to == T) 78 { 79 while (!q.empty()) q.pop(); 80 break; 81 } 82 q.push(to); 83 } 84 } 85 return dep[T]; 86 } 87 88 inline int dinic() 89 { 90 int flow; 91 flow=0; 92 while (bfs()) 93 flow+=dfs(S,inf); 94 return flow; 95 } 96 97 inline void tarjan(int o) 98 { 99 int i,to,cap; 100 dfn[o]=low[o]=++Time; 101 stc[++stc[0]]=o; 102 for (i=f[o]; i; i=eg[i].nx) 103 { 104 to=eg[i].to, cap=eg[i].cap; 105 if (cap > 0) 106 continue; 107 if (!dfn[to]) 108 { 109 tarjan(to); 110 low[o]=min(low[to],low[o]); 111 } 112 else if (!scc[to]) 113 low[o]=min(low[o],dfn[to]); 114 } 115 if (low[o] == dfn[o]) 116 { 117 ++scc[T+1]; 118 do 119 { 120 to=stc[stc[0]--]; 121 scc[to]=scc[T+1]; 122 } 123 while (to != o); 124 } 125 } 126 127 int main() 128 { 129 freopen("sphere.in","r",stdin); 130 freopen("sphere.out","w",stdout); 131 int i,x,y,ans,cap; 132 n=gi(), m=gi(); 133 S=0, T=n+1, num=1, ans=0, n>>=1; 134 for (i=1; i<=m; i++) 135 { 136 x=gi(), y=gi(); 137 add(x,y,1), add(y,x,0); 138 } 139 for (i=1; i<=n; ++i) 140 { 141 add(S,i,1), add(i,S,0); 142 add(i+n,T,1), add(T,i+n,0); 143 } 144 w=dinic(); 145 for (i=S; i<=T; ++i) 146 if (!dfn[i]) 147 tarjan(i); 148 m<<=1, m++; 149 for (i=2; i<=m; i+=2) 150 { 151 cap=eg[i].cap, x=eg[i].to, y=eg[i^1].to; 152 if (cap > 0) 153 continue; 154 if (scc[x] != scc[y]) 155 ans++; 156 } 157 printf("%d\n",ans); 158 return 0; 159 }