标签:art new https dfs iostream usaco inf tar get
P2944 [USACO09MAR]地震损失2Earthquake Damage 2
$P$个点,$C$条双向边。求最少删去几个点使$N$个给定的点与点$1$分开。
显然的最小割。
将点$i$套路地拆成$i_1,i_2$,割点转化成割边
对于点$1$:$link(S,1_1,inf),link(1_1,1_2,inf)$。保证不被割掉,且分到$S$割中
对于每个给定点$k$:$link(k_2,T,inf),link(k_1,k_2,inf)$。保证不被割掉,且分到$T$割中
对于每条双向边$(u,v)$:$link(u_1,v_2,inf),link(u_2,v_1,inf)$。保证不被割掉
对于剩余点:$link(i_1,i_2,1)$。可能被割掉
建好图跑遍最大流(最小割)就好辣
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; #define N 10005 #define M 100005 const int inf=2e9; int n,S,T,d[N],cur[N]; queue <int> h; bool vis[N],e[N]; int cnt=1,hd[N],nxt[M],ed[N],poi[M],val[M]; inline void adde(int x,int y,int v){ nxt[ed[x]]=++cnt, hd[x]=hd[x]?hd[x]:cnt, ed[x]=cnt, poi[cnt]=y, val[cnt]=v; } inline void link(int x,int y,int v){adde(x,y,v),adde(y,x,0);} bool bfs(){ for(int i=1;i<=T;++i) vis[i]=0,cur[i]=hd[i]; h.push(S); vis[S]=1; while(!h.empty()){ int x=h.front(); h.pop(); for(int i=hd[x];i;i=nxt[i]){ int to=poi[i]; if(!vis[to]&&val[i]>0) vis[to]=1,d[to]=d[x]+1,h.push(to); } }return vis[T]; } int dfs(int x,int a){ if(x==T||a==0) return a; int F=0,f; for(int &i=cur[x];i;i=nxt[i]){ int to=poi[i]; if(d[to]==d[x]+1&&(f=dfs(to,min(a,val[i])))>0) a-=f,F+=f,val[i]-=f,val[i^1]+=f; if(!a) break; }return F; } int dinic(){int re=0; while(bfs())re+=dfs(S,inf); return re;} int main(){ int m,c,q1,q2; scanf("%d%d%d",&n,&m,&c); S=n*2+1; T=S+1; link(S,1,inf); link(1,1+n,inf); while(m--){ scanf("%d%d",&q1,&q2); link(q1+n,q2,inf); link(q2+n,q1,inf); } while(c--){ scanf("%d",&q1); e[q1]=1; link(q1,q1+n,inf); link(q1+n,T,inf); } for(int i=1;i<=n;++i) if(!e[i]) link(i,i+n,1); printf("%d",dinic()); return 0; }
P2944 [USACO09MAR]地震损失2Earthquake Damage 2(网络流)
标签:art new https dfs iostream usaco inf tar get
原文地址:https://www.cnblogs.com/kafuuchino/p/10808349.html