bzoj 1458 士兵占领
Posted Forever_goodboy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 1458 士兵占领相关的知识,希望对你有一定的参考价值。
题面:
1458: 士兵占领
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1205 Solved: 663
[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
Solution:
首先判断不合法和容易,如果哪个li>n||cj>m则可以直接输出‘JIONG!’
如果都合法,先不考虑每行和每列重复的部份对答案案贡献,则放置的士兵数量应为∑li+∑cj。
但是肯定会有重复的部份,且每一行每一列重复的士兵数量越多,需要放置的士兵数量越少。
所以问题转化为求最多的重复的士兵数量,将每一行和S连边,容量应为li,同时每一列和T连边,容量为rj,并把有交点的行和列建边,容量为1,
因为只能放一个。
然后跑一遍最大流即可,得到ans,答案应为sum-ans
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 #define min(a,b) ((a)<(b)?(a):(b)) 6 #define max(a,b) ((a)>(b)?(a):(b)) 7 #define inf 100000009 8 int read() { 9 int s=0,f=1; 10 char ch=getchar(); 11 while(ch>‘9‘||ch<‘0‘) { 12 if(ch==‘-‘) { 13 f=-1; 14 } 15 ch=getchar(); 16 } 17 while(ch>=‘0‘&&ch<=‘9‘) { 18 s=(s<<1)+(s<<3)+(ch^48); 19 ch=getchar(); 20 } 21 return s*f; 22 } 23 int n,m,k,l[105],cc[105],S,T; 24 bool wall[105][105]; 25 int tot,r[205],queue[40005],deep[205],head,tail; 26 struct oo { 27 int to,vv,next; 28 } c[40005]; 29 void add(int x,int y,int z) { 30 c[tot].to=y; 31 c[tot].vv=z; 32 c[tot].next=r[x]; 33 r[x]=tot++; 34 } 35 bool bfs(int s,int t) { 36 memset(deep,0,sizeof(deep)); 37 head=tail=0; 38 deep[s]=1; 39 queue[++tail]=s; 40 while(head<tail) { 41 int opt=queue[++head]; 42 for(int i=r[opt]; ~i; i=c[i].next) { 43 if(c[i].vv&&!deep[c[i].to]) { 44 deep[c[i].to]=deep[opt]+1; 45 queue[++tail]=c[i].to; 46 if(c[i].to==t) { 47 return 1; 48 } 49 } 50 } 51 } 52 return 0; 53 } 54 int dfs(int opt,int fw) { 55 if(opt==T) { 56 return fw; 57 } 58 int tmp=fw,k; 59 for(int i=r[opt]; ~i; i=c[i].next) { 60 if(c[i].vv&&tmp&&deep[c[i].to]==deep[opt]+1) { 61 k=dfs(c[i].to,min(tmp,c[i].vv)); 62 if(!k) { 63 deep[c[i].to]=0; 64 continue; 65 } 66 c[i].vv-=k; 67 c[i^1].vv+=k; 68 tmp-=k; 69 } 70 } 71 return fw-tmp; 72 } 73 int dicnic(int s,int t) { 74 int ans=0; 75 while(bfs(s,t)) { 76 ans+=dfs(s,inf); 77 } 78 return ans; 79 } 80 int sum; 81 bool check(){ 82 for(int i=1;i<=m;i++){ 83 if(l[i]>n){ 84 return 0; 85 } 86 } 87 for(int j=1;j<=n;j++){ 88 if(cc[j]>m){ 89 return 0; 90 } 91 } 92 return 1; 93 } 94 int main() { 95 m=read(); 96 n=read(); 97 k=read(); 98 T=n+m+1; 99 memset(r,-1,sizeof(r)); 100 for(int i=1; i<=m; i++) { 101 l[i]=read(); 102 sum+=l[i]; 103 } 104 for(int j=1; j<=n; j++) { 105 cc[j]=read(); 106 sum+=cc[j]; 107 } 108 for(int i=1; i<=k; i++) { 109 int x=read(),y=read(); 110 wall[x][y]=1; 111 } 112 if(!check()){ 113 printf("JIONG!"); 114 return 0; 115 } 116 for(int i=1; i<=m; i++) { 117 add(S,i,l[i]); 118 add(i,S,0); 119 } 120 for(int j=1; j<=n; j++) { 121 add(m+j,T,cc[j]); 122 add(T,m+j,0); 123 } 124 for(int i=1; i<=m; i++) { 125 for(int j=1; j<=n; j++) { 126 if(!wall[i][j]) { 127 add(i,j+m,1); 128 add(j+m,i,0); 129 } 130 } 131 } 132 int ans=dicnic(S,T); 133 printf("%d\n",sum-ans); 134 return 0; 135 }
以上是关于bzoj 1458 士兵占领的主要内容,如果未能解决你的问题,请参考以下文章