P4311 士兵占领[最大流]

题目地址

有一个$M * N$的棋盘,有的格子是障碍。现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵。我们称这些士兵占领了整个棋盘当满足第i行至少放置了$L_i$个士兵, 第j列至少放置了$C_j$个士兵。现在你的任务是要求使用最少个数的士兵来占领整个棋盘。



考虑到说棋盘问题,选的行和列之间是有关联的,彼此制约着数量,就应该可以从网络流入手(然而如果我不是奔网络流刷题来的说不定会瞎写一发dp)

最小化答案,应该对应的是最大流的反向转化(也就是化加为减,求减数最大值,如最小路径覆盖),要不然就是最小割。反正这题辣鸡我是想了一会最小割没想出来才去转化问题的。最少要摆多少个,可以看成把棋盘能摆满的都摆满,再去删去没必要的点。这样的话构建二分图,左点集表示每行,右点集是列。s点向左点集连边容量为$n-L_i-x$ x表示本行障碍数量。容量意思就是我这行最多可以删??那么多点,再删就不合要求啦。右点集同理。$(x,y)$无障碍就在左右点集间连边容量为1,这样一条s到t的通路就是删除一个点$(x,y)$,然后做最大流后用总空格数减最大流即答案。

哦对了记得特判啊。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 typedef pair<int,int> pii;
 5 template<typename T>inline char MIN(T&A,T B){return A<B?A=B,1:0;}
 6 template<typename T>inline char MAX(T&A,T B){return A>B?A=B,1:0;}
 7 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
 8 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
 9 template<typename T>inline T read(T&x){
10     x=0;char c;while(!isdigit(c=getchar()))if(isalpha(c))return x=(int)c;
11     while(isdigit(c))x=(x<<1)+(x<<3)+(c^48),c=getchar();return x;
12 }
13 const int N=200+7,M=10400+7,INF=0x3f3f3f3f;
14 int w[M<<1],v[M<<1],Next[M<<1],Head[N<<1],cur[N<<1],dis[N<<1],tot=1,s,t,n,m;
15 inline void Addedge(int x,int y,int z){
16     v[++tot]=y,Next[tot]=Head[x],Head[x]=tot,w[tot]=z;
17     v[++tot]=x,Next[tot]=Head[y],Head[y]=tot,w[tot]=0;
18 }
19 #define y v[j]
20 inline char bfs(){
21     queue<int> q;q.push(s),memset(dis,0,sizeof dis),dis[s]=1;
22     for(register int i=1;i<=m+n+2;++i)cur[i]=Head[i];
23     while(!q.empty()){
24         int x=q.front();q.pop();
25         for(register int j=Head[x];j;j=Next[j])if(w[j]&&!dis[y]){
26             dis[y]=dis[x]+1,q.push(y);
27             if(y==t)return 1;
28         }
29     }
30     return 0;
31 }
32 int dinic(int x,int flow){
33     if(!flow||x==t)return flow;
34     int rest=flow,k;
35     for(register int j=cur[x];j&&rest;cur[x]=j,j=Next[j])if(w[j]&&dis[y]==dis[x]+1){
36         if(!(k=dinic(y,_min(rest,w[j]))))dis[y]=0;
37         rest-=k,w[j]-=k,w[j^1]+=k;
38     }
39     return flow-rest;
40 }
41 #undef y
42 int a[N][N];
43 int x,y,k,res,cnt;
44
45 int main(){//freopen("tmp.in","r",stdin);freopen("tmp.out","w",stdout);
46     read(n),read(m),read(k);s=n+m+1,t=s+1;
47     for(register int i=1;i<=n;++i)read(a[i][0]),a[i][0]=m-a[i][0];
48     for(register int i=1;i<=m;++i)read(a[0][i]),a[0][i]=n-a[0][i];
49     for(register int i=1;i<=k;++i)read(x),read(y),--a[x][0],--a[0][y],a[x][y]=1;
50     for(register int i=1;i<=_max(n,m);++i)if(a[i][0]<0||a[0][i]<0){printf("JIONG!\n");return 0;}
51     for(register int i=1;i<=n;++i)Addedge(s,i,a[i][0]);
52     for(register int i=n+1;i<=n+m;++i)Addedge(i,t,a[0][i-n]);
53     for(register int i=1;i<=n;++i)for(register int j=1;j<=m;++j)if(!a[i][j])Addedge(i,j+n,1),++cnt;
54     while(bfs())res+=dinic(s,INF);
55     printf("%d\n",cnt-res);
56     return 0;
57 }

原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/10357417.html

时间: 2024-08-04 02:42:19

P4311 士兵占领[最大流]的相关文章

【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: 士兵占领 -- 最大流

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

luogu P4311 士兵占领

又是一道好题...(不会做...) 题意很显然啦... 考虑建模...(有大佬说蓝题..(不知道是不是因为数据水的原因...)) 正解是上下界网络流 当然我不会 于是我使用了一个比较符合胃口(看的顺眼的假方法)---------最大流 直接先补集转换...考虑到正的来,那个至少很棘手 然后至少就变成至多了.... 然后就直接常用方法 S连行,T连列,上线各为他们的总-L 然后对于一个点,直接连他们的行和列,容量为1 然后就直接跑最小割等效于删最多无效点. 然后就没了 嘛,这个题,.... 让我知

【BZOJ1458】士兵占领 最大流的模板题

我们只要把他们可以有的限制用流量限制,再用两者关系限制一下就可以开心的跑了. #include <cstdio> #include <cstring> #include <iostream> #define r register #define N 1005 using namespace std; inline int read() { r int sum=0; r char ch=getchar(); while(ch<'0'||ch>'9')ch=ge

【bzoj1458】士兵占领

Description 有一个M * N的棋盘,有的格子是障碍.现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵.我们称这些士兵占领了整个棋盘当满足第i行至少放置了Li个士兵, 第j列至少放置了Cj个士兵.现在你的任务是要求使用最少个数的士兵来占领整个棋盘. Input 第一行两个数M, N, K分别表示棋盘的行数,列数以及障碍的个数. 第二行有M个数表示Li. 第三行有N个数表示Ci. 接下来有K行,每行两个数X, Y表示(X, Y)这个格子是障碍. O

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

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

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

【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个士兵.现在你的任务是要求使用最少个数的士兵来占领整个棋盘.

1458: 士兵占领

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