zoukankan      html  css  js  c++  java
  • [BZOJ 1458] 士兵占领

    1458: 士兵占领

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

    对于这道题,如果每个士兵仅对某一行或者某一列而不是两者同时作出贡献,则答案$ans$为:

    [ ans=sum_{i=1}^m l_i +sum_{i=1}^n c_i ]

    但是我们知道一些士兵可以同时对某行和某列的和作出贡献,所以我们可以求这样的士兵的最大值,最后用上面求出的假的(ans)减去就可以了

    而求最大值可以考虑网络流,将可以放置士兵的位置的行结点与列结点之间连一条容量为$1$的边,行/列结点分别向源点$s$ / 汇点$t$ 连一条容量为对应需求 $l_i$ 或 $c_i$的边再跑一遍最大流就可以得出结果.

    至于无解情况网络流则无法处理,要在计算最大流之前进行枚举特判.

    参考代码

    GitHub

      1 #include <queue>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <cstdlib>
      5 #include <iostream>
      6 #include <algorithm>
      7 
      8 const int MAXV=210;
      9 const int MAXE=40100;
     10 const int INF=0x7FFFFFFF;
     11 
     12 struct Edge{
     13     int from;
     14     int to;
     15     int flow;
     16     Edge* rev;
     17     Edge* next;
     18 };
     19 
     20 Edge E[MAXE];
     21 Edge* head[MAXV];
     22 Edge* top=E;
     23 
     24 int m;
     25 int n;
     26 int k;
     27 int sum;
     28 int c[MAXV];
     29 int l[MAXV];
     30 int depth[MAXV];
     31 bool flag[MAXV][MAXV];
     32 
     33 int Dinic(int,int);
     34 int DFS(int,int,int);
     35 int Convert(int,int);
     36 bool BFS(int,int);
     37 bool Check();
     38 void Build();
     39 void Initialize();
     40 void Insert(int,int,int);
     41 
     42 int main(){
     43     Initialize();
     44     if(!Check()){
     45         puts("JIONG!");
     46     }
     47     else{
     48         Build();
     49         printf("%d
    ",sum-Dinic(0,m+n+1));
     50     }
     51     return 0;
     52 }
     53 
     54 int Dinic(int s,int t){
     55     int ans=0;
     56     while(BFS(s,t)){
     57         ans+=DFS(s,INF,t);
     58     }
     59     return ans;
     60 }
     61 
     62 int DFS(int s,int flow,int t){
     63     if(s==t||flow==0)
     64         return flow;
     65     int tmp=flow;
     66     int k;
     67     for(Edge* i=head[s];i!=NULL;i=i->next){
     68         if(i->flow!=0&&tmp!=0&&depth[i->to]==depth[s]+1){
     69             k=DFS(i->to,std::min(tmp,i->flow),t);
     70             if(k==0){
     71                 depth[i->to]=0;
     72                 continue;
     73             }
     74             tmp-=k;
     75             i->flow-=k;
     76             i->rev->flow+=k;
     77             if(tmp==0)
     78                 break;
     79         }
     80     }
     81     return flow-tmp;
     82 }
     83 
     84 bool BFS(int s,int t){
     85     memset(depth,0,sizeof(depth));
     86     std::queue<int> q;
     87     q.push(s);
     88     depth[s]=1;
     89     while(!q.empty()){
     90         s=q.front();
     91         q.pop();
     92         for(Edge* i=head[s];i!=NULL;i=i->next){
     93             if(depth[i->to]==0&&i->flow!=0){
     94                 depth[i->to]=depth[s]+1;
     95                 q.push(i->to);
     96                 if(i->to==t)
     97                     return true;
     98             }
     99         }
    100     }
    101     return false;
    102 }
    103 
    104 void Build(){
    105     for(int i=1;i<=m;i++){
    106         for(int j=1;j<=n;j++){
    107             if(!flag[i][j])
    108                 Insert(i,j+m,1);
    109         }
    110     }
    111 }
    112 
    113 void Initialize(){
    114     scanf("%d%d%d",&m,&n,&k);
    115     for(int i=1;i<=m;i++){
    116         scanf("%d",l+i);
    117         Insert(0,i,l[i]);
    118         sum+=l[i];
    119     }
    120     for(int i=1;i<=n;i++){
    121         scanf("%d",c+i);
    122         Insert(i+m,n+m+1,c[i]);
    123         sum+=c[i];
    124     }
    125     int a,b;
    126     for(int i=0;i<k;i++){
    127         scanf("%d%d",&a,&b);
    128         flag[a][b]=true;
    129     }
    130 }
    131 
    132 bool Check(){
    133     int cnt;
    134     for(int i=1;i<=m;i++){
    135         for(int j=1;j<=n;j++){
    136             if(!flag[i][j])
    137                 cnt++;
    138         }
    139         if(cnt<l[i])
    140             return false;
    141     }
    142     for(int j=1;j<=n;j++){
    143         for(int i=1;i<=m;i++){
    144             if(!flag[i][j])
    145                 cnt++;
    146         }
    147         if(cnt<c[j])
    148             return false;
    149     }
    150     return true;
    151 }
    152 
    153 inline void Insert(int a,int b,int flow){
    154     top->from=a;
    155     top->to=b;
    156     top->flow=flow;
    157     top->next=head[a];
    158     head[a]=top;
    159     top->rev=top+1;
    160     top++;
    161     top->from=b;
    162     top->to=a;
    163     top->flow=0;
    164     top->next=head[b];
    165     head[b]=top;
    166     top->rev=top-1;
    167     top++;
    168 }
    Backup

  • 相关阅读:
    0808 HTML 基础
    2016.8.3 C#基础 结构体,枚举类型
    2016.8.1 C#基础 传值
    2016.7.22
    2016.7.20
    2016.7.31C#基础 函数
    2016.07.30C#基础 特殊集合
    2016.7.28C#基础 集合
    个人项目网页3
    个人项目网页2
  • 原文地址:https://www.cnblogs.com/rvalue/p/7263959.html
Copyright © 2011-2022 走看看