bzoj 1458 士兵占领

Posted Forever_goodboy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 1458 士兵占领相关的知识,希望对你有一定的参考价值。

题面:

1458: 士兵占领

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 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

Sample Output

4
数据范围
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 士兵占领的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 1458: 士兵占领 -- 最大流

BZOJ-1458士兵占领 最大流

bzoj1458: 士兵占领 网络流

bzoj1458士兵占领

bzoj 1458: 士兵占领

BZOJ1458: 士兵占领