BZOJ1458:士兵占领(有上下界最小流)
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
Solution
有源汇上下界最小流……按行和列建二分图,分别向源汇点建立上下界为$[L_i,INF]$和$[C_i,INF]$的边,然后没有障碍点的两两连$[0,1]$的边,跑一遍就完了。
一个上下界网络流讲的很好的博客。注意别忘了$s$和$t$也要与$ss$和$tt$连边!
Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<queue> 5 #define N (20009) 6 #define INF (0x7f7f7f7f) 7 using namespace std; 8 9 struct Edge{int to,next,flow;}edge[N*50]; 10 int n,m,k,vis[109][109]; 11 int s=20001,t=20002,ss=20003,tt=20004; 12 int Depth[N],A[N]; 13 int head[N],num_edge; 14 queue<int>q; 15 16 inline int read() 17 { 18 int x=0,w=1; char c=getchar(); 19 while (!isdigit(c)) {if (c=='-') w=-1; c=getchar();} 20 while (isdigit(c)) x=x*10+c-'0', c=getchar(); 21 return x*w; 22 } 23 24 void add(int u,int v,int l) 25 { 26 edge[++num_edge].to=v; 27 edge[num_edge].next=head[u]; 28 edge[num_edge].flow=l; 29 head[u]=num_edge; 30 } 31 32 void Add(int u,int v,int l,int r) 33 { 34 add(u,v,r-l); add(v,u,0); 35 A[u]-=l; A[v]+=l; 36 } 37 38 int DFS(int x,int low,int t) 39 { 40 if (x==t || !low) return low; 41 int f=0; 42 for (int i=head[x]; i; i=edge[i].next) 43 if (Depth[edge[i].to]==Depth[x]+1) 44 { 45 int Min=DFS(edge[i].to,min(low,edge[i].flow),t); 46 edge[i].flow-=Min; 47 edge[((i-1)^1)+1].flow+=Min; 48 f+=Min; low-=Min; 49 if (!low) break; 50 } 51 if (!f) Depth[x]=-1; 52 return f; 53 } 54 55 bool BFS(int s,int t) 56 { 57 memset(Depth,0,sizeof(Depth)); 58 Depth[s]=1; q.push(s); 59 while (!q.empty()) 60 { 61 int x=q.front(); q.pop(); 62 for (int i=head[x]; i; i=edge[i].next) 63 if (!Depth[edge[i].to] && edge[i].flow) 64 { 65 Depth[edge[i].to]=Depth[x]+1; 66 q.push(edge[i].to); 67 } 68 } 69 return Depth[t]; 70 } 71 72 int Dinic(int s,int t) 73 { 74 int ans=0; 75 while (BFS(s,t)) ans+=DFS(s,INF,t); 76 return ans; 77 } 78 79 int main() 80 { 81 n=read(); m=read(); k=read(); s=n+m+1; t=s+1; 82 for (int i=1; i<=n; ++i) Add(s,i,read(),INF); 83 for (int i=1; i<=m; ++i) Add(i+n,t,read(),INF); 84 for (int i=1; i<=k; ++i) vis[read()][read()]=1; 85 for (int i=1; i<=n; ++i) 86 for (int j=1; j<=m; ++j) 87 if (!vis[i][j]) Add(i,j+n,0,1); 88 int sum=0; 89 for (int i=1; i<=n+m+2; ++i) 90 if (A[i]>0) sum+=A[i], add(ss,i,A[i]), add(i,ss,0); 91 else add(i,tt,-A[i]), add(tt,i,0); 92 add(t,s,INF); add(s,t,0); 93 if (Dinic(ss,tt)!=sum) {puts("JIONG!"); return 0;} 94 for (int i=head[ss]; i; i=edge[i].next) edge[i].flow=edge[((i-1)^1)+1].flow=0; 95 for (int i=head[tt]; i; i=edge[i].next) edge[i].flow=edge[((i-1)^1)+1].flow=0; 96 int flow0=edge[num_edge].flow; 97 edge[num_edge].flow=edge[num_edge-1].flow=0; 98 printf("%d\n",flow0-Dinic(t,s)); 99 }