BZOJ 1458: 士兵占领 最大流
判断有没有解:让所有没有障碍的格子都放一个士兵.
那么,题中要求最少放几个士兵,就是最多拿走几个士兵.
而由于行和列对士兵个数都是由要求的,这就规定了拿走的士兵的上界.
跑一个最大流来求就行了.
code:
#include <cstdio> #include <queue> #include <algorithm> #include <cstring> #include <vector> #define N 302 #define inf 10005 #define setIO(s) freopen(s".in","r",stdin) using namespace std; int s,t; int vis[N]; int d[N]; int gr[N][N]; int M[N],a[N],b[N]; struct Edge { int u,v,c; Edge(int u=0,int v=0,int c=0):u(u),v(v),c(c){} }; queue<int>q; vector<Edge>edges; vector<int>G[N]; void add(int u,int v,int c) { edges.push_back(Edge(u,v,c)); edges.push_back(Edge(v,u,0)); int o=edges.size(); G[u].push_back(o-2); G[v].push_back(o-1); } int dfs(int x,int cur) { if(x==t) return cur; int an=0,flow=0; for(int i=0;i<G[x].size();++i) { Edge e=edges[G[x][i]]; if(e.c>0&&d[e.v]==d[x]+1) { an=dfs(e.v,min(cur,e.c)); if(an) { cur-=an; flow+=an; edges[G[x][i]].c-=an; edges[G[x][i]^1].c+=an; if(!cur) break; } } } return flow; } int bfs() { memset(vis,0,sizeof(vis)); d[s]=0; vis[s]=1; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); for(int i=0;i<G[u].size();++i) { if(edges[G[u][i]].c>0) { int v=edges[G[u][i]].v; if(!vis[v]) { vis[v]=1; d[v]=d[u]+1; q.push(v); } } } } return vis[t]; } int maxflow() { int re=0; while(bfs()) { re+=dfs(s,inf); } return re; } int main() { // setIO("input"); int i,j,n,m,k; scanf("%d%d%d",&n,&m,&k); for(i=1;i<=n;++i) scanf("%d",&a[i]); for(i=1;i<=m;++i) scanf("%d",&b[i]); for(i=1;i<=k;++i) { int x,y; scanf("%d%d",&x,&y); gr[y][x]=1; } for(i=1;i<=n;++i) { int re=0; for(j=1;j<=m;++j) { re+=gr[i][j]; } M[i]=m-re-a[i]; } for(i=1;i<=m;++i) { int re=0; for(j=1;j<=n;++j) { re+=gr[j][i]; } M[i+n]=n-re-b[i]; } for(i=1;i<=n+m;++i) { if(M[i]<0) { printf("JIONG!\n"); return 0; } } s=0,t=n+m+1; for(i=1;i<=n;++i) { add(s,i,M[i]); for(j=n+1;j<=n+m;++j) { add(i,j,1); } } for(i=n+1;i<=n+m;++i) { add(i,t,M[i]); } printf("%d\n",m*n-k-maxflow()); return 0; }