bzoj1458: 士兵占领
逆向思维:最少多少士兵=最多放多少空格。于是跑最大流就OK了。取行列为节点。
#include<cstdio> #include<cstring> #include<iostream> #include<cmath> #include<algorithm> using namespace std; #define rep(i,n) for(int i=1;i<=n;i++) #define clr(x,c) memset(x,c,sizeof(x)) #define REP(i,s,t) for(int i=s;i<=t;i++) #define op() clr(head,0);pt=edges; #define qwq(x) for(edge *o=head[x];o;o=o->next) int read(){ int x=0;char c=getchar();bool f=true; while(!isdigit(c)) { if(c=='-') f=false;c=getchar(); } while(isdigit(c)) x=x*10+c-'0',c=getchar(); return x; } const int nmax=205; const int maxn=1000005; const int inf=0x7f7f7f7f; struct edge{ int to,cap;edge *next,*rev; }; edge edges[maxn],*pt,*head[nmax],*p[nmax],*cur[nmax]; int cnt[nmax],h[nmax],g[nmax][nmax],ni[nmax][2],mi[nmax][2]; void add(int u,int v,int w){ pt->to=v;pt->cap=w;pt->next=head[u];head[u]=pt++; } void adde(int u,int v,int w){ add(u,v,w);add(v,u,0);head[u]->rev=head[v];head[v]->rev=head[u]; } int maxflow(int s,int t,int n){ clr(cnt,0);cnt[0]=n;clr(h,0); int flow=0,a=inf,x=s;edge *e; while(h[s]<n){ for(e=cur[x];e;e=e->next) if(e->cap>0&&h[x]==h[e->to]+1) break; if(e){ a=min(a,e->cap);p[e->to]=cur[x]=e;x=e->to; if(x==t){ while(x!=s) p[x]->cap-=a,p[x]->rev->cap+=a,x=p[x]->rev->to; flow+=a,a=inf; } }else{ if(!--cnt[h[x]]) break; h[x]=n; for(e=head[x];e;e=e->next) if(e->cap>0&&h[x]>h[e->to]+1) h[x]=h[e->to]+1,cur[x]=e; cnt[h[x]]++; if(x!=s) x=p[x]->rev->to; } } return flow; } int main(){ op();clr(ni,0);clr(mi,0);clr(g,1); int n=read(),m=read(),k=read(),u,v,s=0,t=n+m+1; rep(i,n) ni[i][0]=ni[i][1]=read(); rep(i,m) mi[i][0]=ni[i][1]=read(); rep(i,k) u=read(),v=read(),ni[u][0]++,mi[v][0]++,g[u][v]=0; rep(i,n) if(ni[i][0]>m){ printf("JIONG!\n") ;return 0; } rep(j,m) if(mi[j][0]>n){ printf("JIONG!\n") ;return 0; } rep(i,n) adde(s,i,m-ni[i][0]); rep(i,m) adde(i+n,t,n-mi[i][0]); rep(i,n) rep(j,m) if(g[i][j]) adde(i,n+j,1); /*REP(i,s,t) { qwq(i) printf("%d ",o->to);printf("\n"); }*/ printf("%d\n",n*m-k-maxflow(s,t,t+1)); return 0; }
1458: 士兵占领
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 897 Solved: 505
[Submit][Status][Discuss]
Description
有一个M * N的棋盘,有的格子是障碍。现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵。我们称这些士兵占领了整个棋盘当满足第i行至少放置了Li个士兵, 第j列至少放置了Cj个士兵。现在你的任务是要求使用最少个数的士兵来占领整个棋盘。
Input
第一行两个数M, N, K分别表示棋盘的行数,列数以及障碍的个数。 第二行有M个数表示Li。 第三行有N个数表示Ci。 接下来有K行,每行两个数X, Y表示(X, Y)这个格子是障碍。
Output
输出一个数表示最少需要使用的士兵个数。如果无论放置多少个士兵都没有办法占领整个棋盘,输出”JIONG!” (不含引号)
Sample Input
4 4 4
1 1 1 1
0 1 0 3
1 4
2 2
3 3
4 3
1 1 1 1
0 1 0 3
1 4
2 2
3 3
4 3
Sample Output
4
数据范围
M, N <= 100, 0 <= K <= M * N
数据范围
M, N <= 100, 0 <= K <= M * N