【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\n",tot-ans);
86 }
时间: 2024-10-24 09:13:05

【bzoj1458】士兵占领的相关文章

bzoj1458: 士兵占领

逆向思维:最少多少士兵=最多放多少空格.于是跑最大流就OK了.取行列为节点. #include<cstdio> #include<cstring> #include<iostream> #include<cmath> #include<algorithm> using namespace std; #define rep(i,n) for(int i=1;i<=n;i++) #define clr(x,c) memset(x,c,sizeo

bzoj1458: 士兵占领 网络流

链接 https://www.lydsy.com/JudgeOnline/problem.php?id=1458 也可以去luogu 思路 想成倒着删去点,使得依旧满足覆盖!! 左边横,右边列,之间用点链接起来,流量1 S到i为之间总公共 最多去掉m-h[i]-L[i]个,i到T同理. 代码 #include <iostream> #include <queue> #include <cstdio> #include <cstring> const int

【BZOJ-1458】士兵占领 最大流

1458: 士兵占领 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 782  Solved: 456[Submit][Status][Discuss] Description 有一个M * N的棋盘,有的格子是障碍.现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵.我们称这些士兵占领了整个棋盘当满足第i行至少放置了Li个士兵, 第j列至少放置了Cj个士兵.现在你的任务是要求使用最少个数的士兵来占领整个棋盘.

[BZOJ 1458]士兵占领(网络流)

Description 有一个M * N的棋盘,有的格子是障碍.现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵.我们称这些士兵占领了整个棋盘当满足第i行至少放置了Li个士兵, 第j列至少放置了Cj个士兵.现在你的任务是要求使用最少个数的士兵来占领整个棋盘. Solution 可以用上下界最小流来做,不过我觉得黄学长的这个思路也很直接 将每行每列都看成一个点,由s向行连边,容量为可以放置的士兵数-至少放置的士兵数 由列向t连边,容量为可以放置的士兵数-至少

1458: 士兵占领

1458: 士兵占领 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1044  Solved: 598[Submit][Status][Discuss] Description 有一个M * N的棋盘,有的格子是障碍.现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵.我们称这些士兵占领了整个棋盘当满足第i行至少放置了Li个士兵, 第j列至少放置了Cj个士兵.现在你的任务是要求使用最少个数的士兵来占领整个棋盘.

【BZOJ 1458】 士兵占领

1458: 士兵占领 Time Limit: 10 Sec Memory Limit: 64 MB Submit: 632 Solved: 366 [Submit][Status][Discuss] Description 有一个M * N的棋盘,有的格子是障碍.现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵.我们称这些士兵占领了整个棋盘当满足第i行至少放置了Li个士兵, 第j列至少放置了Cj个士兵.现在你的任务是要求使用最少个数的士兵来占领整个棋盘.

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

1458: 士兵占领 Time Limit: 10 Sec  Memory Limit: 64 MB Description 有一个M * N的棋盘,有的格子是障碍.现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵.我们称这些士兵占领了整个棋盘当满足第i行至少放置了Li个士兵, 第j列至少放置了Cj个士兵.现在你的任务是要求使用最少个数的士兵来占领整个棋盘. Input 第一行两个数M, N, K分别表示棋盘的行数,列数以及障碍的个数. 第二行有M个数表示

[bzoj 1458] 士兵占领(网络流dinic)

1458: 士兵占领 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 784  Solved: 458[Submit][Status][Discuss] Description 有一个M * N的棋盘,有的格子是障碍.现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵.我们称这些士兵占领了整个棋盘当满足第i行至少放置了Li个士兵, 第j列至少放置了Cj个士兵.现在你的任务是要求使用最少个数的士兵来占领整个棋盘.

P4311 士兵占领[最大流]

题目地址 有一个$M * N$的棋盘,有的格子是障碍.现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵.我们称这些士兵占领了整个棋盘当满足第i行至少放置了$L_i$个士兵, 第j列至少放置了$C_j$个士兵.现在你的任务是要求使用最少个数的士兵来占领整个棋盘. 考虑到说棋盘问题,选的行和列之间是有关联的,彼此制约着数量,就应该可以从网络流入手(然而如果我不是奔网络流刷题来的说不定会瞎写一发dp) 最小化答案,应该对应的是最大流的反向转化(也就是化加为减,求