【系列】网络流
bzoj 1934 善意的投票
题目大意:
每个人可以选择睡不睡午觉 给出他们原本的意愿 以及m对朋友表示他们之间应当选择相同 求好朋友之间发生冲突的总数加上和所有和自己本来意愿发生冲突的人数
思路:
每个意愿不同的人分别连向源和汇 对于一对朋友之间连边 这样最小割即可
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 #include<cstring> 7 #include<vector> 8 #include<queue> 9 #include<complex> 10 #include<map> 11 #define rep(i,s,t) for(register int i=(s);i<=(t);++i) 12 #define dwn(i,s,t) for(register int i=(s);i>=(t);--i) 13 #define ren for(register int i=fst[x];i;i=nxt[i]) 14 #define Fill(x,t) memset(x,t,sizeof(x)) 15 #define ll long long 16 #define Cd complex<double> 17 #define inf 2139062143 18 #define MOD 998244353 19 #define MAXN 310 20 #define MAXM 90100 21 using namespace std; 22 inline int read() 23 { 24 int x=0,f=1;char ch=getchar(); 25 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 26 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 27 return x*f; 28 } 29 int n,m,S,T; 30 struct Dinic 31 { 32 int fst[MAXN],cur[MAXN],nxt[MAXM<<1],to[MAXM<<1],val[MAXM<<1]; 33 int vis[MAXN],dep[MAXN],tot,cnt,q[MAXN],l,r; 34 void mem(){memset(fst,0,sizeof(fst));cnt=1;} 35 void add(int u,int v,int w){nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w;} 36 void ins(int u,int v,int w){add(u,v,w);add(v,u,0);} 37 int bfs() 38 { 39 q[l=r=1]=T,vis[T]=++tot,dep[T]=0;int x; 40 while(l<=r) 41 { 42 x=q[l++]; 43 ren if(val[i^1]&&vis[to[i]]!=tot) {vis[to[i]]=tot,dep[to[i]]=dep[x]+1,q[++r]=to[i];if(to[i]==S)return 1;} 44 } 45 return vis[S]==tot; 46 } 47 int dfs(int x,int now) 48 { 49 if(x==T||!now) return now; 50 int flow=0,f; 51 for(int& i=cur[x];i;i=nxt[i]) 52 if(val[i]&&dep[to[i]]==dep[x]-1&&(f=dfs(to[i],min(now,val[i])))) 53 {now-=f,flow+=f,val[i]-=f,val[i^1]+=f;if(!now) break;} 54 return flow; 55 } 56 int solve() 57 { 58 int ans=0,f; 59 while(bfs()) {memcpy(cur,fst,sizeof(cur));while(f=dfs(S,inf)) ans+=f;} 60 return ans; 61 } 62 }D; 63 int main() 64 { 65 n=read(),m=read(),S=0,T=n+1;D.mem();int a,b;rep(i,1,n) {a=read();if(a) D.ins(S,i,1);else D.ins(i,T,1);} 66 rep(i,1,m) a=read(),b=read(),D.ins(a,b,1),D.ins(b,a,1); 67 printf("%d\n",D.solve()); 68 }
bzoj 1066 蜥蜴
题目大意:
一个网格图,一开始有一些蜥蜴,一些网格上有石柱,每个石柱在被一个蜥蜴离开之后高度会减一 ,减为0后就不能被跳了
每只蜥蜴只能从一个石柱跳到不超过d的距离的石柱上去 求最少不能出去的蜥蜴数量
思路:
对于每个石柱拆成两个点 中间连一条边来满足这个石柱的限制
其余的就从每个石柱的第二个点连向可以跳到石柱的第一个点 最后用总数-最大流即可
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 #include<cstring> 7 #include<vector> 8 #include<queue> 9 #include<complex> 10 #include<map> 11 #define rep(i,s,t) for(register int i=(s);i<=(t);++i) 12 #define dwn(i,s,t) for(register int i=(s);i>=(t);--i) 13 #define ren for(register int i=fst[x];i;i=nxt[i]) 14 #define Fill(x,t) memset(x,t,sizeof(x)) 15 #define ll long long 16 #define Cd complex<double> 17 #define inf 2139062143 18 #define MOD 998244353 19 #define MAXN 510 20 #define MAXM 320100 21 using namespace std; 22 inline int read() 23 { 24 int x=0,f=1;char ch=getchar(); 25 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 26 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 27 return x*f; 28 } 29 int n,m,d,S,T,all; 30 struct Dinic 31 { 32 int fst[MAXN],cur[MAXN],nxt[MAXM<<1],to[MAXM<<1],val[MAXM<<1]; 33 int vis[MAXN],dep[MAXN],tot,cnt,q[MAXN],l,r; 34 void mem(){memset(fst,0,sizeof(fst));cnt=1;} 35 void add(int u,int v,int w){nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w;} 36 void ins(int u,int v,int w){add(u,v,w);add(v,u,0);} 37 int bfs() 38 { 39 q[l=r=1]=T,vis[T]=++tot,dep[T]=0;int x; 40 while(l<=r) 41 { 42 x=q[l++]; 43 ren if(val[i^1]&&vis[to[i]]!=tot) {vis[to[i]]=tot,dep[to[i]]=dep[x]+1,q[++r]=to[i];if(to[i]==S)return 1;} 44 } 45 return vis[S]==tot; 46 } 47 int dfs(int x,int now) 48 { 49 if(x==T||!now) return now; 50 int flow=0,f; 51 for(int& i=cur[x];i;i=nxt[i]) 52 if(val[i]&&dep[to[i]]==dep[x]-1&&(f=dfs(to[i],min(now,val[i])))) 53 {now-=f,flow+=f,val[i]-=f,val[i^1]+=f;if(!now) break;} 54 return flow; 55 } 56 int solve() 57 { 58 int ans=0,f; 59 while(bfs()) {memcpy(cur,fst,sizeof(cur));while(f=dfs(S,inf)) ans+=f;} 60 return ans; 61 } 62 }D; 63 char mp[25][25],ch[25]; 64 int cur[25][25]; 65 void srch(int x,int y) 66 { 67 if(mp[x][y]=='0') return ; 68 if((x-d<1||x+d>n||y-d<1||y+d>m)) D.ins(cur[x][y]+1,T,inf); 69 rep(i,x-d,x+d) if(i<1||i>n) continue; 70 else rep(j,y-d,y+d) if(j<1||j>m) continue; 71 else if(abs(x-i)+abs(y-j)<=d) D.ins(cur[x][y]+1,cur[i][j],inf); 72 } 73 int main() 74 { 75 n=read(),m=read(),d=read(),S=0,T=(n*m+2)<<1,all=1;int num=0;D.mem(); 76 rep(i,1,n) {scanf("%s",mp[i]+1);rep(j,1,m) {if(mp[i][j]!='0') D.ins(all,all+1,mp[i][j]-'0');cur[i][j]=all,all+=2;}} 77 rep(i,1,n) {scanf("%s",ch+1);rep(j,1,m) {srch(i,j);if(ch[j]=='L') D.ins(S,cur[i][j],1),num++;}} 78 printf("%d",num-D.solve()); 79 }
bzoj 4625 水晶
题目大意:
思路:
首先根据题意发现题为一个三分图 由于b共振的条件
因此把坐标和%3位0的放在中间 剩下两个顺序随意 通过拆点来满足价值 用总数-最小割即可
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 #include<cstring> 7 #include<vector> 8 #include<queue> 9 #include<complex> 10 #include<map> 11 #define rep(i,s,t) for(register int i=(s);i<=(t);++i) 12 #define dwn(i,s,t) for(register int i=(s);i>=(t);--i) 13 #define ren for(register int i=fst[x];i;i=nxt[i]) 14 #define Fill(x,t) memset(x,t,sizeof(x)) 15 #define ll long long 16 #define Cd complex<double> 17 #define inf 2139062143 18 #define MOD 998244353 19 #define MAXN 100100 20 #define MAXM 400100 21 using namespace std; 22 inline int read() 23 { 24 int x=0,f=1;char ch=getchar(); 25 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 26 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 27 return x*f; 28 } 29 int n,m,S,T,x[MAXN],y[MAXN],z[MAXN]; 30 double all,d[MAXN]; 31 int calc(int x,int y) {return 4000*(x+2000)+y+6000;} 32 map <int,int> hsh; 33 struct Dinic 34 { 35 int fst[MAXN],cur[MAXN],nxt[MAXM<<1],to[MAXM<<1];double val[MAXM<<1]; 36 int vis[MAXN],dep[MAXN],tot,cnt,q[MAXN],l,r; 37 void mem(){memset(fst,0,sizeof(fst));cnt=1;} 38 void add(int u,int v,double w){nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w;} 39 void ins(int u,int v,double w){add(u,v,w);add(v,u,0.0);} 40 int bfs() 41 { 42 q[l=r=1]=T,vis[T]=++tot,dep[T]=0;int x; 43 while(l<=r) 44 { 45 x=q[l++]; 46 ren if(val[i^1]>0.0&&vis[to[i]]!=tot) {vis[to[i]]=tot,dep[to[i]]=dep[x]+1,q[++r]=to[i];if(to[i]==S)return 1;} 47 } 48 return vis[S]==tot; 49 } 50 double dfs(int x,double now) 51 { 52 if(x==T||now==0.0) return now; 53 double flow=0,f; 54 for(int& i=cur[x];i;i=nxt[i]) 55 if(val[i]>0.0&&dep[to[i]]==dep[x]-1&&((f=dfs(to[i],min(now,val[i])))!=0.0)) 56 {now-=f,flow+=f,val[i]-=f,val[i^1]+=f;if(!now) break;} 57 return flow; 58 } 59 double solve() 60 { 61 double ans=0,f; 62 while(bfs()) {memcpy(cur,fst,sizeof(cur));while((f=dfs(S,inf))!=0.0) ans+=f;} 63 return ans; 64 } 65 }D; 66 int main() 67 { 68 n=read(),S=(n+3)<<1,T=((n+3)<<1|1);D.mem();int tmp,to;rep(i,1,n) 69 { 70 x[i]=read(),y[i]=read(),z[i]=read(),d[i]=read(); 71 if((x[i]+y[i]+z[i])%3==0) d[i]*=1.1;all+=d[i]; 72 tmp=hsh[to=calc(x[i]-=z[i],y[i]-=z[i])]; 73 if(!tmp) hsh[to]=tmp=i;D.ins(tmp<<1,tmp<<1|1,d[i]); 74 } 75 rep(i,1,n) 76 { 77 tmp=hsh[to=calc(x[i],y[i])];if(tmp!=i) continue; 78 if((x[i]+y[i]+33333)%3==1) D.ins(i<<1|1,T,inf); 79 else 80 { 81 if((x[i]+y[i]+33333)%3==2) D.ins(S,i<<1,inf); 82 D.ins(i<<1|1,hsh[calc(x[i],y[i]+1)]<<1,inf); 83 D.ins(i<<1|1,hsh[calc(x[i]+1,y[i])]<<1,inf); 84 D.ins(i<<1|1,hsh[calc(x[i]-1,y[i]-1)]<<1,inf); 85 } 86 } 87 printf("%.1lf\n",all-D.solve()); 88 }
bzoj 1391 order
题目大意:
n个任务 m个机器 每个任务都需要一些机器 一个机器可以租借或购买 具有不同的价格
每个机器对不同的任务租借费用不同 任务的利润和机器的购买价格相等
思路:
若不考虑租借 则为最大权闭合子图 考虑修改这个图 对于原来流量为inf的边修改为相应的租借费用
这样对于一条$S\rightarrow T$的路径,总会有一条边被割掉,即为买机器或租借某一个机器或者不要这个收益
用总收益减去最小割即为答案
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 #include<cstring> 7 #include<vector> 8 #include<queue> 9 #include<complex> 10 #include<map> 11 #define rep(i,s,t) for(register int i=(s);i<=(t);++i) 12 #define dwn(i,s,t) for(register int i=(s);i>=(t);--i) 13 #define ren for(register int i=fst[x];i;i=nxt[i]) 14 #define Fill(x,t) memset(x,t,sizeof(x)) 15 #define ll long long 16 #define Cd complex<double> 17 #define inf 2139062143 18 #define MOD 998244353 19 #define MAXN 2510 20 #define MAXM 1500100 21 using namespace std; 22 inline int read() 23 { 24 int x=0,f=1;char ch=getchar(); 25 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 26 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 27 return x*f; 28 } 29 int n,m,S,T,all; 30 struct Dinic 31 { 32 int fst[MAXN],cur[MAXN],nxt[MAXM<<1],to[MAXM<<1],val[MAXM<<1]; 33 int vis[MAXN],dep[MAXN],tot,cnt,q[MAXN],l,r; 34 void mem(){memset(fst,0,sizeof(fst));cnt=1;} 35 void add(int u,int v,int w){nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w;} 36 void ins(int u,int v,int w){add(u,v,w);add(v,u,0);} 37 int bfs() 38 { 39 q[l=r=1]=T,vis[T]=++tot,dep[T]=0;int x; 40 while(l<=r) 41 { 42 x=q[l++]; 43 ren if(val[i^1]&&vis[to[i]]!=tot){vis[to[i]]=tot,dep[to[i]]=dep[x]+1,q[++r]=to[i];if(to[i]==S)return 1;} 44 } 45 return vis[S]==tot; 46 } 47 int dfs(int x,int now) 48 { 49 if(x==T||!now) return now;int flow=0,f; 50 for(int& i=cur[x];i;i=nxt[i]) 51 if(val[i]&&dep[to[i]]==dep[x]-1&&(f=dfs(to[i],min(now,val[i])))) 52 {now-=f,flow+=f,val[i]-=f,val[i^1]+=f;if(!now) break;} 53 return flow; 54 } 55 int solve() 56 { 57 int ans=0,f; 58 while(bfs()) {memcpy(cur,fst,sizeof(cur));while(f=dfs(S,inf)) ans+=f;} 59 return ans; 60 } 61 }D; 62 int main() 63 { 64 n=read(),m=read(),S=n+m+5,T=S+1;D.mem();int a,b,c;rep(i,1,n) 65 { 66 a=read(),all+=a;D.ins(S,i,a);a=read();rep(j,1,a) 67 b=read(),c=read(),D.ins(i,b+n,c); 68 } 69 rep(i,1,m) a=read(),D.ins(i+n,T,a); 70 printf("%d\n",all-D.solve()); 71 }
bzoj 1070 修车
题目大意:
m个人修n辆车,不同的人修不同的车需要不同的时间,求所有人最短修完车的时间(包含等待时间)
思路:
把每个人拆成n个点,表示第$i$个倒数第$j$个修哪辆车
这样倒数第$j$个的影响就是$j$倍的影响(会影响加上自己的$j$个人的等待时间)
1 // luogu-judger-enable-o2 2 // luogu-judger-enable-o2 3 #include<iostream> 4 #include<cstdio> 5 #include<cmath> 6 #include<cstdlib> 7 #include<cstring> 8 #include<algorithm> 9 #include<vector> 10 #include<queue> 11 #include<map> 12 #include<set> 13 #include<complex> 14 #include<iomanip> 15 #define Fill(a,x) memset(a,x,sizeof(a)) 16 #define rep(i,s,t) for(register int i=(s),i__end=(t);i<=i__end;++i) 17 #define dwn(i,s,t) for(register int i=(s),i__end=(t);i>=i__end;--i) 18 #define ren for(int i=fst[x];i;i=nxt[i]) 19 #define inf 2139062143 20 #define ll long long 21 #define ull unsigned long long 22 #define MAXN 710 23 #define MAXM 40010 24 #define MOD 998244353 25 using namespace std; 26 inline int read() 27 { 28 int x=0,f=1;char ch=getchar(); 29 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 30 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 31 return x*f; 32 } 33 int S,T,n,m,g[70][70]; 34 struct zkw 35 { 36 int fst[MAXN],nxt[MAXM<<1],to[MAXM<<1],cst[MAXM<<1],val[MAXM<<1],cnt; 37 int q[MAXN<<4],hd,tl,vis[MAXN],tot,dis[MAXN];ll ans; 38 zkw(){Fill(fst,0);cnt=1,ans=0LL;} 39 void add(int u,int v,int w,int c) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,cst[cnt]=c,val[cnt]=w;} 40 void ins(int u,int v,int w,int c) {add(u,v,w,c);add(v,u,0,-c);} 41 int spfa() 42 { 43 Fill(vis,0);Fill(dis,127);q[hd=tl=1]=T,dis[T]=0;int x; 44 while(hd<=tl) 45 { 46 x=q[hd++],vis[x]=0; 47 ren if(val[i^1]&&dis[to[i]]>dis[x]-cst[i]) 48 {dis[to[i]]=dis[x]-cst[i];if(!vis[to[i]]) vis[to[i]]=1,q[++tl]=to[i];} 49 } 50 return dis[S]!=inf; 51 } 52 int dfs(int x,int a) 53 { 54 if(x==T||!a) {ans+=dis[S]*a;return a;} 55 if(vis[x]) return 0;vis[x]=1;int f,flw=0; 56 ren if(val[i]&&dis[to[i]]==dis[x]-cst[i]&&(f=dfs(to[i],min(a,val[i])))) 57 {flw+=f,val[i]-=f,val[i^1]+=f,a-=f;if(!a) break;} 58 return flw; 59 } 60 int solve(int res=0) 61 { 62 while(spfa()) res+=dfs(S,inf);return res; 63 } 64 }Z; 65 int main() 66 { 67 n=read(),m=read();S=n*m+m+1,T=S+1;rep(i,1,n*m) Z.ins(S,i,1,0); 68 rep(i,1,m) Z.ins(i+n*m,T,1,0);rep(i,1,m) rep(j,1,n) g[i][j]=read(); 69 rep(i,1,n) rep(j,1,m) rep(k,1,m) Z.ins((i-1)*m+j,n*m+k,1,j*g[k][i]); 70 Z.solve();printf("%.2lf\n",1.0*Z.ans/m); 71 }
bzoj 3894 文理分科
题目大意:
每个人可以选文理科分别得到两种价值$a$或$b$
若这个人的四连块中的人选课都与他一样则会得到附加的$c$或$d$
思路:
每个人拆成三个点 第一个点表示自己 分别与源汇点连边表示选文或理
第二个点连向包括自己和相邻的五个点的第一个点 容量为inf(因为不能被割) 从源向该点连边容量为附加的文科值
第三个点与第二个点类似表示理科
这样的话使用总代价-最小割即为答案
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #define ll long long 12 #define inf 2139062143 13 #define MAXN 30500 14 #define MAXM 300100 15 #define MOD 998244353 16 #define rep(i,s,t) for(register int i=(s),i##__end=(t);i<=i##__end;++i) 17 #define dwn(i,s,t) for(register int i=(s),i##__end=(t);i>=i##__end;--i) 18 #define ren for(register int i=fst[x];i;i=nxt[i]) 19 #define pb(i,x) vec[i].push_back(x) 20 #define pls(a,b) (a+b)%MOD 21 #define mns(a,b) (a-b+MOD)%MOD 22 #define mul(a,b) (1LL*(a)*(b))%MOD 23 using namespace std; 24 inline int read() 25 { 26 int x=0,f=1;char ch=getchar(); 27 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 28 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 29 return x*f; 30 } 31 int n,m,S,T,sum,dx[5]={1,-1,0,0,0},dy[5]={0,0,1,-1,0}; 32 struct Dinic 33 { 34 int fst[MAXN],nxt[MAXM<<1],to[MAXM<<1],val[MAXM<<1],cnt; 35 int q[MAXN],l,r,vis[MAXN],dep[MAXN],cur[MAXN],tot; 36 Dinic(){memset(fst,0,sizeof(fst));memset(vis,0,sizeof(vis));cnt=1,tot=0;} 37 void add(int u,int v,int w) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w;} 38 void ins(int u,int v,int w) {add(u,v,w);add(v,u,0);} 39 int bfs() 40 { 41 vis[T]=++tot,q[l=r=1]=T,dep[T]=0;int x; 42 while(l<=r) 43 { 44 x=q[l++];ren if(vis[to[i]]!=tot&&val[i^1]) 45 vis[to[i]]=tot,dep[to[i]]=dep[x]+1,q[++r]=to[i]; 46 } 47 return vis[S]==tot; 48 } 49 int dfs(int x,int a) 50 { 51 if(x==T||!a) return a;int flw=0,f; 52 for(int& i=cur[x];i&&a;i=nxt[i]) 53 if(val[i]&&dep[to[i]]==dep[x]-1&&(f=dfs(to[i],min(a,val[i])))) 54 flw+=f,a-=f,val[i]-=f,val[i^1]+=f; 55 return flw; 56 } 57 int solve() 58 { 59 int ans=0,f; 60 while(bfs()){memcpy(cur,fst,sizeof(cur));while(f=dfs(S,inf)) ans+=f;} 61 return ans; 62 } 63 }D; 64 int ok(int x,int y) {return x>=0&&x<=n&&y>=0&&y<=m;} 65 int calc(int k,int x,int y) {return k*(n+1)*(m+1)+x*(m+1)+y;} 66 int main() 67 { 68 n=read()-1,m=read()-1,S=3*(n+1)*(m+1)+1,T=S+1;int x,nx,ny; 69 rep(i,0,n) rep(j,0,m) {x=read(),sum+=x;D.ins(S,calc(0,i,j),x);} 70 rep(i,0,n) rep(j,0,m) {x=read(),sum+=x;D.ins(calc(0,i,j),T,x);} 71 rep(i,0,n) rep(j,0,m) 72 { 73 x=read(),sum+=x;rep(k,0,4) if(ok(nx=(i+dx[k]),(ny=j+dy[k]))) 74 D.ins(calc(1,i,j),calc(0,nx,ny),inf); 75 D.ins(S,calc(1,i,j),x); 76 } 77 rep(i,0,n) rep(j,0,m) 78 { 79 x=read(),sum+=x;rep(k,0,4) if(ok(nx=(i+dx[k]),(ny=j+dy[k]))) 80 D.ins(calc(0,nx,ny),calc(2,i,j),inf); 81 D.ins(calc(2,i,j),T,x); 82 } 83 printf("%d\n",sum-D.solve()); 84 }
bzoj 1143 祭祀
题目大意:
求DAG的最长反链(一个点集使其两两不可达
思路:
最长反链=最小链覆盖
求最小链覆盖需要把每个点拆成两个,每个能到达的点对,由左边的$u$连向右边的$v$ ,求最大点独立集
最大点独立集=$n$-最大匹配
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #define ll long long 12 #define db double 13 #define inf 2139062143 14 #define MAXN 510 15 #define MAXM 100300 16 #define rep(i,s,t) for(register int i=(s),i##__end=(t);i<=i##__end;++i) 17 #define dwn(i,s,t) for(register int i=(s),i##__end=(t);i>=i##__end;--i) 18 #define ren for(register int i=fst[x];i;i=nxt[i]) 19 #define pb(i,x) vec[i].push_back(x) 20 #define pls(a,b) (a+b)%MOD 21 #define mns(a,b) (a-b+MOD)%MOD 22 #define mul(a,b) (1LL*(a)*(b))%MOD 23 using namespace std; 24 inline int read() 25 { 26 int x=0,f=1;char ch=getchar(); 27 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 28 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 29 return x*f; 30 } 31 int n,m,S,T,mp[110][110]; 32 struct Dinic 33 { 34 int fst[MAXN],nxt[MAXM<<1],to[MAXM<<1],val[MAXM<<1],cnt,cur[MAXN]; 35 int vis[MAXN],dis[MAXN],tot,q[MAXN],l,r; 36 Dinic(){memset(fst,0,sizeof(fst));cnt=1;} 37 void add(int u,int v,int w) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w;} 38 void ins(int u,int v,int w) {add(u,v,w);add(v,u,0);} 39 int bfs() 40 { 41 q[l=r=1]=T,vis[T]=++tot,dis[T]=0;int x; 42 while(l<=r) 43 { 44 x=q[l++];ren if(vis[to[i]]!=tot&&val[i^1]) 45 dis[to[i]]=dis[x]+1,vis[to[i]]=tot,q[++r]=to[i]; 46 } 47 return vis[S]==tot; 48 } 49 int dfs(int x,int a) 50 { 51 if(x==T||!a) return a;int flw=0,f; 52 for(int& i=cur[x];i&&a;i=nxt[i]) 53 if(dis[to[i]]==dis[x]-1&&val[i]&&(f=dfs(to[i],min(a,val[i])))) 54 a-=f,flw+=f,val[i]-=f,val[i^1]+=f; 55 return flw; 56 } 57 int solve(int res=0) 58 { 59 int f;while(bfs()) 60 {rep(i,1,T) cur[i]=fst[i];while(f=dfs(S,inf)) res+=f;} 61 return res; 62 } 63 }D; 64 int main() 65 { 66 n=read(),m=read();int a,b;S=n<<1|1,T=S+1; 67 while(m--) a=read(),b=read(),mp[a][b]=1; 68 rep(k,1,n) rep(i,1,n) rep(j,1,n) mp[i][j]|=(mp[i][k]&mp[k][j]); 69 rep(i,1,n) rep(j,1,n) if(mp[i][j]) D.ins(i,j+n,1); 70 rep(i,1,n) D.ins(S,i,1),D.ins(i+n,T,1); 71 printf("%d\n",n-D.solve()); 72 }