这是一道网络流好题。
门外都在放鞭炮,没心思码字了。。 就简单说说思路。
先判断无解的情况: 只要有一行(或列)能放士兵的格子数小于L[i](或C[i])则无解。这很显然对吧。 在有解的情况下,把所有空格子都放上士兵显然是可以满足约束条件的,但是不够优。我们要做的就是填满士兵后,再拿掉尽可能多的士兵,并要满足约束条件。
所以可以如下构图:
源S向每一行连边,容量为该行能放的士兵数减去L[i]
每一列向汇T连边,容量为该列能放的士兵数减去C[i]
对于行x和列y,若(x,y)点可以放士兵, 则x向y连边, 容量为1(因为每个格子只能放1个士兵)
对这个图跑最大流. 跑出来的结果是什么呢? 显然就是最大能删去的士兵数. 然后因为这个构图中已经减去了L[i]与C[i],因此每一个可行流都对应着一种合法的删士兵方案。最大流显然是合法方案中删士兵数最大的。
答案就是所有空格子数量减去最大流,即n*m-maxflow
祝大家新年快乐
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#define INF 2100000000
using namespace std;
struct node
{
int p,next,w;
}edge[100000];
int cnt=1;
int head[10000],cur[10000],s,t,h[10000];
queue<int> q;
void insert(int a,int b,int c)
{
edge[++cnt].p=b;
edge[cnt].w=c;
edge[cnt].next=head[a];
head[a]=cnt;
edge[++cnt].p=a;
edge[cnt].w=0;
edge[cnt].next=head[b];
head[b]=cnt;
}
bool bfs()
{
memset(h, 0xff, sizeof h);
for (int i=1;i<=t;++i) cur[i]=head[i];
h[s]=1;
while (!q.empty()) q.pop();
q.push(s);
while (!q.empty())
{
int u=q.front();q.pop();
for (int k=head[u];k;k=edge[k].next)
{
int v=edge[k].p;
if (edge[k].w>0&&h[v]==-1)
{
h[v]=h[u]+1;
q.push(v);
if (v==t) return true;
}
}
}
return false;
}
int dfs(int u,int now)
{
if (u==t) return now;
int res=0,tmp;
for (int &k=cur[u];k;k=edge[k].next)
{
int v=edge[k].p;
if (edge[k].w>0&&h[v]==h[u]+1)
{
tmp=dfs(v,min(edge[k].w,now));
res+=tmp;
edge[k].w-=tmp;
edge[k^1].w+=tmp;
if (!(now-=tmp)) break;
}
}
if (!res) h[u]=-1;
return res;
}
int dinic()
{
int ans=0;
while (bfs()) ans+=dfs(s,INF);
return ans;
}
int n,m,sum,k;
int line[200],col[200];
int ban[200][200];
int main()
{
cin>>n>>m>>k;
sum=n*m;
s=n+m+1,t=n+m+2;
for (int i=1;i<=n;++i) {scanf("%d",&line[i]);line[i]=m-line[i];}
for (int i=1;i<=m;++i) {scanf("%d",&col[i]);col[i]=n-col[i];}
for (int i=1;i<=k;++i)
{
int x,y;
scanf("%d%d",&x,&y);
if (!ban[x][y])
{
line[x]--;
col[y]--;
sum--;
}
ban[x][y]=1;
}
for (int i=1;i<=n;++i)
if (line[i]<0) {cout<<"JIONG!"<<endl;return 0;}
else insert(s,i,line[i]);
for (int i=1;i<=m;++i)
if (col[i]<0) {cout<<"JIONG!"<<endl;return 0;}
else insert(i+n,t,col[i]);
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j)
if (!ban[i][j]) insert(i,j+n,1);
cout<<sum-dinic()<<endl;
return 0;
}