解法:
首先考虑逆向思维,求最少要使用的士兵个数,转化为,初始的时候所有能放士兵的地方都放了士兵的情况下,最多能删掉多少个士兵。
1. 给每一行每一列分别建一个点,对于所有非障碍坐标(x,y),从x行对应的点 向 y列对应的点连一条容量为1的边,表示这个位置的士兵最多可以删除一次。
2. 源点向每一行对应的点连边,容量为这一行能删除的士兵个数的最大值(即 列数m - 这一行的障碍数 - 这一行需要的士兵数L[i])。
3. 每一列对应的点向汇点连边,容量为这一列能删除的士兵个数的最大值(即 行数n - 这一列的障碍数 - 这一列需要的士兵数C[i])。
这样跑一个最大流,每一个单位的流量表示删除一个士兵,不难证明 任意一种流量状态都与一种合法的士兵删除方案相对应。
特判无解的情况,如果所有能放士兵的地方都放上了士兵,仍然存在行或列不满足限制条件,输出无解即可。
copy from: https://www.luogu.com.cn/blog/user36456/solution-p4311
Code:
1 #include <bits/stdc++.h> 2 #define LL long long 3 #define INF 0x3f3f3f3f; 4 using namespace std; 5 6 int M, N, K; 7 int row[110], col[110]; 8 int grid[110][110]; 9 int S, T; 10 int maxsub; 11 struct Edge{ 12 int next, from, to, remain; 13 }e[25000]; 14 int en; 15 int head[300]; 16 queue<int> q; 17 int visited[300]; 18 int preEdge[300]; 19 int minflow[300]; 20 21 void addEdge(int from, int to, int flow){ 22 e[en].next=head[from]; 23 e[en].from=from; 24 e[en].to=to; 25 e[en].remain=flow; 26 head[from]=en; 27 ++en; 28 } 29 30 void add(int from, int to, int flow){ 31 addEdge(from, to, flow); 32 addEdge(to, from, 0); 33 } 34 35 void bfs(){ 36 memset(visited,0,sizeof(visited)); 37 memset(preEdge,-1,sizeof(preEdge)); 38 memset(minflow,0,sizeof(minflow)); 39 q.push(S); 40 visited[S]=1; 41 minflow[S]=INF; 42 while(!q.empty()){ 43 int u=q.front(); 44 q.pop(); 45 for(int i=head[u];i!=-1;i=e[i].next){ 46 if(e[i].remain>0 && !visited[e[i].to]){ 47 visited[e[i].to]=1; 48 minflow[e[i].to]=min(minflow[u],e[i].remain); 49 preEdge[e[i].to]=i; 50 q.push(e[i].to); 51 } 52 } 53 } 54 } 55 56 void EK(){ 57 while(true){ 58 bfs(); 59 if(preEdge[T]==-1) break; 60 maxsub+=minflow[T]; 61 int v=T; 62 while(true){ 63 int edge=preEdge[v]; 64 if(edge==-1) break; 65 e[edge].remain-=minflow[T]; 66 e[edge^1].remain+=minflow[T]; 67 v=e[edge].from; 68 } 69 } 70 } 71 72 int main(){ 73 memset(head,-1,sizeof(head)); 74 scanf("%d %d %d", &M, &N, &K); 75 for(int i=1;i<=M;++i){ 76 scanf("%d", row+i); 77 } 78 for(int i=1;i<=N;++i){ 79 scanf("%d", col+i); 80 } 81 for(int i=1;i<=K;++i){ 82 int x,y; 83 scanf("%d %d", &x, &y); 84 grid[x][y]=1; 85 } 86 S=0; 87 T=M+N+1; 88 for(int i=1;i<=M;++i){ 89 int blocks=0; 90 for(int j=1;j<=N;++j){ 91 if(grid[i][j]){ 92 blocks++; 93 }else{ 94 add(i,j,1); 95 } 96 } 97 if(N-blocks-row[i]<0) { 98 printf("JIONG!"); 99 return 0; 100 } 101 add(S,i,N-blocks-row[i]); 102 } 103 104 for(int j=1;j<=N;++j){ 105 int blocks=0; 106 for(int i=1;i<=M;++i){ 107 if(grid[i][j]) blocks++; 108 } 109 if(M-blocks-col[j]<0){ 110 printf("JIONG!"); 111 return 0; 112 } 113 add(j,T,M-blocks-col[j]); 114 } 115 116 EK(); 117 int res=M*N-K-maxsub; 118 printf("%d", res); 119 return 0; 120 }