zoukankan      html  css  js  c++  java
  • 【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

    Sample Output

    4

    题解:

      最大流第一题。orz黄学长。

      问最小需要点数转化一下,就是最大能不放的位置。以S为原点,向每行连一条容量为n-l[i]-在该行上不能放置点数,以T为汇点,每列向T连一条m-c[i]-在该列上不能放置数的边。再把每行对应的点与可以连接的列对应点连一条容量为1的边,最大流显然就是要求的最大数。

      然后用总点数减去这些就行。

     1 #include<cstdio>
     2 #include<cstring>
     3 const int T=201;
     4 const int S=0;
     5 inline int min(int a,int b){return a<b?a:b;}
     6 inline int read(){
     7     char ch=getchar();
     8     int f=1,x=0;
     9     while(!(ch>='0'&&ch<='9')){if(ch=='-')f=-1;ch=getchar();}
    10     while(ch>='0'&&ch<='9'){x=x*10+(ch-'0');ch=getchar();}
    11     return x*f;
    12 }
    13 int m,n,k;
    14 const int N=110;
    15 int l[N],c[N];
    16 bool vis[N][N],used[N];
    17 int rel[N],rec[N];
    18 int tot,ans;
    19 struct edges {
    20     int v,cap;edges *last;
    21 }edge[N<<8],*head[N<<8],*cur[N<<8];int cnt;
    22 inline void insert(int u,int v,int w){
    23     edge[cnt].v=v;edge[cnt].last=head[u];edge[cnt].cap=w;head[u]=edge+cnt;cnt++;
    24     edge[cnt].v=u;edge[cnt].last=head[v];edge[cnt].cap=0;head[v]=edge+cnt;cnt++;
    25 }
    26 int q[N<<5];
    27 int dis[N<<5];
    28 int h,t;
    29 bool bfs(){
    30     memset(dis,0,sizeof(dis));
    31     dis[S]=1,q[1]=S;h=t=1;
    32     int u,v;
    33     while(h<=t){
    34         u=q[h++];
    35         for(edges *i=head[u];i;i=i->last)
    36             if(i->cap&&!dis[i->v])
    37                 dis[i->v]=dis[u]+1,q[++t]=i->v;
    38     }
    39     if(dis[T]) return 1;
    40     else return 0;
    41 }
    42  
    43 int dfs(int u,int w){
    44     if(u==T||w==0) return w;
    45     int ret=0;
    46     for(edges *i=head[u];i;i=i->last)if(i->cap&&(dis[i->v]==dis[u]+1)){
    47         int f=dfs(i->v,min(i->cap,w));
    48         i->cap-=f,edge[(i-edge)^1].cap+=f;
    49         w-=f,ret+=f;
    50         if(!w) break;
    51     }
    52     if(!ret) dis[u]=-1;
    53     return ret;
    54 }
    55  
    56 inline int dinic(){
    57     int ret=0;
    58     while(bfs()) ret+=dfs(S,0x7fffffff);
    59     return ret;
    60 }
    61 int main()
    62 {
    63     m=read(),n=read(),k=read();
    64     for(int i=1;i<=m;i++)
    65         l[i]=n-read();
    66     for(int i=1;i<=n;i++)
    67         c[i]=m-read(); 
    68     for(int i=1,x,y;i<=k;i++)
    69     {
    70         x=read(),y=read();
    71         vis[x][y]=1;
    72         rel[x]++,rec[y]++;
    73         if(rel[x]>l[x]){puts("JIONG!");return 0;}
    74         if(rel[y]>l[y]){puts("JIONG!");return 0;}
    75     }
    76     tot=n*m-k;
    77     for(int i=1;i<=m;i++)
    78         insert(0,i,l[i]-rel[i]);
    79     for(int i=1;i<=n;i++)
    80         insert(m+i,T,c[i]-rec[i]);
    81     for(int i=1;i<=m;i++)
    82         for(int j=1;j<=n;j++)
    83             if(!vis[i][j])insert(i,j+m,1);
    84     ans=dinic();
    85     printf("%d
    ",tot-ans);
    86 }
  • 相关阅读:
    linux grep --我最喜欢的命令~~
    svmrank 的误差惩罚因子c选择 经验
    转:机器学习中的算法(2)-支持向量机(SVM)基础
    转:关于python文件操作大全
    python 求两个时间差
    多个excel合并(excel2007)
    oracle12c 新建表空间
    数据库表被锁了
    join ,left join ,right join有什么区别
    最简洁的权限(菜单)控制
  • 原文地址:https://www.cnblogs.com/Troywar/p/7257275.html
Copyright © 2011-2022 走看看