BZOJ 1458 士兵占领

http://www.lydsy.com/JudgeOnline/problem.php?id=1458

题意:n x m的棋盘,k个位置不能放,每行和每列都有要求至少的士兵,求能否有最少的满足条件的士兵放法是多少。

思路:先全放满求能否满足,再尽量删掉士兵:

对于每行:能放m[i],至少放c[i],就从S连向i:m[i]-c[i],代表能删的最大

对于每列:能放m[i],至少放c[i],就从i+n连向T:m[i]-c[i],代表能删的最大

这样对于i,j这个位置如果可以放士兵,那就从i行连向j+n,流量为1,共享删掉1个

求最大流,就等于最小割,得到的就是能删的最多,然后答案就是Σm1[i]-最大流

 1 #include<algorithm>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<iostream>
 6 #define inf 0x7fffffff
 7 int tot,go[200005],next[200005],flow[200005],first[200005];
 8 int op[200005],nodes,T,S,dis[200005],cnt[200005],pd[105][105],n,m,k;
 9 int m1[200005],m2[200005],c1[200005],c2[200005];
10 int read(){
11     int t=0,f=1;char ch=getchar();
12     while (ch<‘0‘||ch>‘9‘){if (ch==‘-‘) f=-1;ch=getchar();}
13     while (‘0‘<=ch&&ch<=‘9‘){t=t*10+ch-‘0‘;ch=getchar();}
14     return t*f;
15 }
16 void insert(int x,int y,int z){
17     tot++;
18     go[tot]=y;
19     next[tot]=first[x];
20     first[x]=tot;
21     flow[tot]=z;
22 }
23 void add(int x,int y,int z){
24     insert(x,y,z);op[tot]=tot+1;
25     insert(y,x,0);op[tot]=tot-1;
26 }
27 int dfs(int x,int f){
28     if (x==T) return f;
29     int mn=nodes,sum=0;
30     for (int i=first[x];i;i=next[i]){
31         int pur=go[i];
32         if (flow[i]&&dis[pur]+1==dis[x]){
33             int save=dfs(pur,std::min(f-sum,flow[i]));
34             flow[i]-=save;
35             flow[op[i]]+=save;
36             sum+=save;
37             if (sum==f||dis[S]>=nodes) return sum;
38         }
39         if (flow[i]) mn=std::min(mn,dis[pur]);
40     }
41     if (sum==0){
42         cnt[dis[x]]--;
43         if (cnt[dis[x]]==0){
44             dis[S]=nodes;
45         }else{
46             dis[x]=mn+1;
47             cnt[dis[x]]++;
48         }
49     }
50     return sum;
51 }
52 int main(){
53     n=read();m=read();k=read();
54     S=0,T=n+m+1;nodes=T+1;
55     int sum1=0,sum2=0;
56     for (int i=1;i<=n;i++){
57         int x=read();
58         sum1+=x;
59         m1[i]=x;
60     }
61     for (int i=1;i<=m;i++){
62         int x=read();
63         sum2+=x;
64         m2[i]=x;
65     }
66     for (int i=1;i<=k;i++){
67         int x=read(),y=read();
68         pd[x][y]=1;
69     }
70     int ans=0;
71     for (int i=1;i<=n;i++)
72      for (int j=1;j<=m;j++)
73       if (!pd[i][j])
74        c1[i]++,c2[j]++;
75     int sx=0;
76     for (int i=1;i<=n;i++)
77      sx+=c1[i];
78     for (int i=1;i<=n;i++)
79      if (c1[i]<m1[i]) {
80             printf("JIONG!\n");return 0;
81      }
82      for (int i=1;i<=m;i++)
83       if (c2[i]<m2[i]){
84             printf("JIONG!\n");return 0;
85       }
86     for (int i=1;i<=n;i++)
87      add(S,i,c1[i]-m1[i]);
88     for (int i=1;i<=m;i++)
89      add(i+n,T,c2[i]-m2[i]);
90     for (int i=1;i<=n;i++)
91      for (int j=1;j<=m;j++)
92       if (!pd[i][j])
93        add(i,j+n,1);
94     while (dis[S]<nodes) ans+=dfs(S,inf);
95     ans=sx-ans;
96     printf("%d\n",ans);
97 }
时间: 2024-10-27 07:56:42

BZOJ 1458 士兵占领的相关文章

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

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

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

BZOJ 1458 士兵占领 Dinic最大流

题目大意:给定一个m*n的棋盘,其中k个点有障碍,要求放置最少的士兵,使第i行有至少L[i]个,第j列有至少C[j]个 首先这种问题很明显的网络流 但是正图肯定是跑不了 限制条件是至少而且要求放置的也是最少 很难解决 反向考虑 将棋盘上先放满士兵 此时若不能满足条件则无解 然后求最多能撤掉多少个士兵 其中第i行最多撤去templ[i]-l[i]个士兵 templ[i]表示第i行当前放置的士兵个数 尼玛我的网络流是多久不写了--居然没连反向弧就跑样例--最逗的是数组开小一倍不报RE报WA-- #i

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

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】士兵占领

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