题目大意:给定一个m*n的棋盘,其中k个点有障碍,要求放置最少的士兵,使第i行有至少L[i]个,第j列有至少C[j]个
首先这种问题很明显的网络流 但是正图肯定是跑不了 限制条件是至少而且要求放置的也是最少 很难解决
反向考虑 将棋盘上先放满士兵 此时若不能满足条件则无解 然后求最多能撤掉多少个士兵 其中第i行最多撤去templ[i]-l[i]个士兵 templ[i]表示第i行当前放置的士兵个数
尼玛我的网络流是多久不写了……居然没连反向弧就跑样例……最逗的是数组开小一倍不报RE报WA……
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 110 #define s 0 #define t (m+n+1) #define INF 0x3f3f3f3f using namespace std; struct abcd{ int to,f,next; }table[M*M<<1]; int head[M+M],tot=1; int m,n,k,ans; int l[M],c[M]; int templ[M],tempc[M]; bool ban[M][M]; int d[M+M]; void Add(int x,int y,int z) { table[++tot].to=y; table[tot].f=z; table[tot].next=head[x]; head[x]=tot; } bool BFS() { int i; static int q[65540]; static unsigned short r,h; r=h=0; memset(d,-1,sizeof d); d[s]=0;q[++r]=s; while(r!=h) { int x=q[++h]; for(i=head[x];i;i=table[i].next) if(table[i].f) { if(~d[table[i].to]) continue; d[table[i].to]=d[x]+1; q[++r]=table[i].to; if(table[i].to==t) return true; } } return false; } int Dinic(int x,int flow) { int i,left=flow; if(x==t) return flow; for(i=head[x];i&&left;i=table[i].next) if(table[i].f&&d[table[i].to]==d[x]+1) { int temp=Dinic(table[i].to,min(left,table[i].f)); if(!temp) d[table[i].to]=-1; left-=temp; table[i].f-=temp; table[i^1].f+=temp; } return flow-left; } int main() { int i,j,x,y; cin>>m>>n>>k; for(i=1;i<=m;i++) scanf("%d",&l[i]),templ[i]=n; for(i=1;i<=n;i++) scanf("%d",&c[i]),tempc[i]=m; for(i=1;i<=k;i++) { scanf("%d%d",&x,&y); if(--templ[x]<l[x]) { puts("JIONG!"); return 0; } if(--tempc[y]<c[y]) { puts("JIONG!"); return 0; } ban[x][y]=true; } ans=m*n-k; for(i=1;i<=m;i++) for(j=1;j<=n;j++) if(!ban[i][j]) Add(i,m+j,1),Add(m+j,i,0); for(i=1;i<=m;i++) Add(s,i,templ[i]-l[i]),Add(i,s,0); for(i=1;i<=n;i++) Add(m+i,t,tempc[i]-c[i]),Add(t,m+i,0); while( BFS() ) ans-=Dinic(s,INF); cout<<ans<<endl; }
原文地址:http://blog.csdn.net/popoqqq/article/details/40791459