暂无链接
签到?
【问题描述】
这题有毒!
豆豆有一个n×mn×m的棋盘,一开始所有的格子都是黑的,可以选择一些黑色的格子把它们变成白色。
豆豆想知道问至少选多少个格子,可以使得每一列满足,该列白格数量≥Xi≥Xi,每行满足,该行白格数量≥Yi≥Yi。
当然没有这么简单,还有些格子必须是黑色的。
【输入格式】
第一行n,m,Kn,m,K。分别表示行数、列数、不能选的格子数。
第二行nn个数表示。
第三行mm个数表示。
接下来KK行,每行两个数描述一个不能选的格子。
【输出格式】
如果要求可以达到,输出一行一个整数表示最少选择的格子。
否则输出“”(不含引号)。
【输入样例】
4 4 4
1 1 1 1
0 1 0 3
1 4
2 2
3 3
4 3
【输出样例】
4
【数据范围】
对于30%30%的数据,0<n,m≤100<n,m≤10。
对于100%100%的数据,0<n,m≤100,0≤K≤nm0<n,m≤100,0≤K≤nm。
题解
左边nn个点,右边个点,连n×mn×m条边表示每个格子,如果边被流了就表示该格子被选了。
源点向代表行的点连边,容量为XiXi;代表列的点再向汇点连边,容量为YiYi。但是这样就需要跑有上下界的网络流,实际上可以把网格看成初始为白色的倒着做,就没有下界的限制了。
至于在考场上。。。当然有算法就打啊,有上下界的网络流贼溜。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=405,M=1e5+5,inf=0x3f3f3f3f;
struct sd{int to,fl;}ed[M];
int id,cnt,ss,tt,s,t,n,m,k,pre,head[N],nxt[M],num[M],d[N],x[N],y[N];
queue<int>dui;
bool GG[N][N];
void added(int f,int t,int w){nxt[++cnt]=head[f],head[f]=cnt,num[cnt]=id;ed[id++]=(sd){t,w};}
void add(int f,int t,int w){added(f,t,w),added(t,f,0);}
bool bfs(int s,int t)
{
memset(d,0,sizeof(d));
dui.push(s);d[s]=1;
int f,to,fl;
while(!dui.empty())
{
f=dui.front();dui.pop();
for(int i=head[f];i;i=nxt[i])
{
to=ed[num[i]].to,fl=ed[num[i]].fl;
if(d[to]||!fl)continue;
d[to]=d[f]+1;
dui.push(to);
}
}
return d[t];
}
int dfs(int v,int t,int minn)
{
if(v==t||!minn)return minn;
int to,fl,tmp,ans=0;
for(int i=head[v];i;i=nxt[i])
{
to=ed[num[i]].to,fl=ed[num[i]].fl;
if(d[to]!=d[v]+1||!fl)continue;
tmp=dfs(to,t,min(minn-ans,fl));
ed[num[i]].fl-=tmp,ed[num[i]^1].fl+=tmp;
ans+=tmp;
}
return ans;
}
void in()
{
int a,b,c;
scanf("%d%d%d",&n,&m,&k);t=n+m+1,ss=400,tt=401;
add(t,s,inf);
for(int i=1;i<=n;++i)scanf("%d",&x[i]),add(ss,i,x[i]),add(s,tt,x[i]),add(s,i,inf);
for(int i=1;i<=m;++i)scanf("%d",&y[i]),add(ss,t,y[i]),add(i+n,tt,y[i]),add(i+n,t,inf);pre=id;
for(int i=1;i<=k;++i)scanf("%d%d",&a,&b),GG[a][b]=1;
for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)if(!GG[i][j])add(i,j+n,1);
}
void ac()
{
int ans=0;
while(bfs(ss,tt))dfs(ss,tt,inf);
for(int i=head[ss];i;i=nxt[i])if(ed[num[i]].fl)puts("IIllIIll1!"),exit(0);
ed[1].fl=ed[2].fl=0;
for(int i=head[ss];i;i=nxt[i])ed[num[i]].fl=ed[num[i]^1].fl=0;
for(int i=head[tt];i;i=nxt[i])ed[num[i]].fl=ed[num[i]^1].fl=0;
while(bfs(t,s))dfs(t,s,inf);
for(int i=pre;i<id;i+=2)if(!ed[i].fl)ans++;
printf("%d",ans);
}
int main(){in();ac();}

本文介绍了一个关于网络流算法的实际问题:在一个给定的棋盘上,通过选择最少数量的格子变为白色,来满足每行每列特定的白色格子数量要求。文章详细解释了如何构建网络流模型,并给出了具体的实现代码。

被折叠的 条评论
为什么被折叠?



