洛谷P4311 士兵占领
题目
https://www.luogu.com.cn/problem/P4311
思路
网格+行列个数限制,很明显地可以看出是网络流的模型了,但是比较棘手的是它给定限定是下界而不是上界。
考虑上下界网络流?但是窝太蒻了不会。
但是我们可以用普通的最大流解决这道题。
可以发现,本题与常见模型的唯一区别就是"至少"和“至多”,那么,换个思路想想,“至少” \(x\) 个兵,在格数为 \(m\) 的一行是不是就意味着“至多” \(m-x\) 个空格子?
这启示我们可以以空格作为研究对象建图,这就转成了最经典的网格图行列限制问题。
用最大流跑出最多放多少新的空格,加上原来钦定的空格,就是最多的空格数,再用\(n*m\)一减就完事了。
特判一下无解的情况。
水过去了,结果上下界网络流还是不会QwQ。
代码
点击查看代码
#include<cstdio>
#include<cstdlib>
#include<queue>
#define maxe 30000
#define inf 0x3f3f3f3f
using namespace std;
int n,m,S,T;
int fst[300],nxt[maxe],cnt=0;
int MAP[101][101];
int deep[300],vis[300];
int lim1[300],lim2[300];
int c1[300],c2[300];
struct edge{
int u,v,cap;
edge(){}
edge(int x,int y,int z){
u=x,v=y,cap=z;
}
} e[maxe];
void read(int &x){
int ans=0;
char c=getchar();
while(!(c>='0'&&c<='9')) c=getchar();
while(c>='0'&&c<='9'){
ans=ans*10+c-'0';
c=getchar();
}
x=ans;
return;
}
void add(int x,int y,int z){
e[++cnt]=edge(x,y,z);
nxt[cnt]=fst[x];
fst[x]=cnt;
}
int inv(int x){
return (x&1)?x+1:x-1;
}
int bfs(){
queue<int> q;
for(int i=1;i<=T;++i) vis[i]=deep[i]=0;
vis[S]=1;
q.push(S);
while(!q.empty()){
int p=q.front();
q.pop();
for(int i=fst[p];i;i=nxt[i]){
if(!e[i].cap) continue;
if(!vis[e[i].v]){
vis[e[i].v]=1;
q.push(e[i].v);
deep[e[i].v]=deep[p]+1;
}
}
}
return vis[T];
}
int dfs(int x,int flow){
int i,tot_flow=0;
if(x==T||!flow) return flow;
for(i=fst[x];i;i=nxt[i]){
if(deep[e[i].v]==deep[x]+1){
int f=dfs(e[i].v,min(flow,e[i].cap));
e[i].cap-=f;
e[inv(i)].cap+=f;
flow-=f;
tot_flow+=f;
if(!flow) break;
}
}
return tot_flow;
}
int check(){
int i,j;
for(i=1;i<=n;++i){
if(c1[i]+lim1[i]>m) return 0;
}
for(i=1;i<=m;++i){
if(c2[i]+lim2[i]>n) return 0;
}
return 1;
}
int maxflow(){
int flow=0;
while(bfs()){
flow+=dfs(S,inf);
}
return flow;
}
int main(){
int i,j,k,x,y,z;
int ans;
read(n);read(m);read(k);
S=n+m+1;T=S+1;
for(i=1;i<=n;++i) read(lim1[i]);
for(i=1;i<=m;++i) read(lim2[i]);
for(i=1;i<=k;++i){
read(x);read(y);
MAP[x][y]=1;
c1[x]++;c2[y]++;
}
if(!check()){
printf("JIONG!");
return 0;
}
for(i=1;i<=n;++i){
for(j=1;j<=m;++j){
if(MAP[i][j]^1){
add(i,n+j,1);
add(n+j,i,0);
}
}
}
for(i=1;i<=n;++i){
if(m-lim1[i]-c1[i]){
add(S,i,m-lim1[i]-c1[i]);
add(i,S,0);
}
}
for(i=1;i<=m;++i){
if(n-lim2[i]-c2[i]){
add(n+i,T,n-lim2[i]-c2[i]);
add(T,n+i,0);
}
}
ans=n*m-maxflow()-k;
printf("%d",ans);
// system("pause");
return 0;
}