标签:左右 continue std cstring include 一个 pop for code
题目大意就是要从歹徒要从s点运送货物到t点,警察在一些城市拦截,在每一个城市拦截都有一定的花费,问最小花费是多少可以拦截住歹徒。
呐,在某些点设置障碍,使得整张图不能在联通,我们知道一个类似的问题:割断某些点使得图不能再联通——最小割问题,那么把这些点拆了,点权变为边权,不就是最小割问题了么,我们知道最小割等于最大流,所以这就是一个拆点+网络流的问题。
代码:
#include<iostream> #include<cstring> #include<cstdio> #include<queue> using namespace std; const int maxn=2100,maxm=50005; const int inf=2147483647; int n,m; int S,T; int x,y; struct zhw{ int to,last,val; }tu[maxm<<2]; int tot,head[maxn]; void add(int x,int y,int v) { tot++,tu[tot].last=head[x],head[x]=tot,tu[tot].to=y,tu[tot].val=v; tot++,tu[tot].last=head[y],head[y]=tot,tu[tot].to=x,tu[tot].val=0; } int ans; bool vis[maxn]; int dis[maxn]; queue<int>q; bool bfs() { memset(vis,0,sizeof(vis)); memset(dis,0,sizeof(dis)); q.push(S);vis[S]=1;dis[S]=1; while(!q.empty()) { int k=q.front();q.pop(); for(int i=head[k];i;i=tu[i].last) { if(!vis[tu[i].to]&&tu[i].val) { vis[tu[i].to]=1; dis[tu[i].to]=dis[k]+1; q.push(tu[i].to); } } } return vis[T]; } int m_flow(int now,int lim) { if(!lim||now==T)return lim; int flow=0,f; for(int i=head[now];i;i=tu[i].last) { if(dis[tu[i].to]==dis[now]+1&&tu[i].val>0) { f=m_flow(tu[i].to,min(lim,tu[i].val)); if(!f)continue; flow+=f,lim-=f; tu[i].val-=f,tu[i^1].val+=f; if(!lim)break; } } if(!flow)dis[now]=-1; return flow; } int main() { while(scanf("%d%d",&n,&m)!=EOF) { scanf("%d%d",&x,&y); S=x,T=y; tot=1,memset(head,0,sizeof(head)); add(S,x,inf),add(y+n,T,inf); for(int i=1;i<=n;++i) { scanf("%d",&x); add(i,i+n,x);//这就是拆点的部分,把一个点拆成左右两部分,这个点的入边必然是从左边入,出边必然是从右边出,边权是原来的点权 } for(int i=1;i<=m;++i) { scanf("%d%d",&x,&y); add(x+n,y,inf);//如上,既然是自己约束自己,必然是左边进右边出,路是双向边,没有约束,所以流量是正无穷 add(y+n,x,inf); } ans=0; T=T+n;//这里一定要注意,最后肯定是要跑到右边的T才可以呀,我一开始就是这里错了 while(bfs()) { ans+=m_flow(S,inf); } printf("%d\n",ans); } return 0; }
标签:左右 continue std cstring include 一个 pop for code
原文地址:https://www.cnblogs.com/yuelian/p/12301079.html