4.2 省选模拟赛 摆棋子 网络流 最大流/上下界最小流
题意:n×m的棋盘 有k个格子坏了不能放棋子 每个好的格子只能放一个棋子 至少要摆多少个棋子满足行的棋子个数>=\(x_i\)列的棋子个数>=\(y_i\)
\(n,m\leq 100,k\leq nm\)
网络流经典题目 不过好久没做了 还是有点菜。
显然 可以考虑二分 结果发现dp不了 看n,m的范围考虑网络流。
有限制,将行列当成二分的节点 格子相当于连边 可以跑流了 发现源点向每一行的流量>=\(x_i\)汇点对列也是如此。
有上下界的最小流即可。但是这种做法并不推荐 (因为这是强行在套模板 尽管思路简单。
而且这个最小流 有些细节可能容易写挂。譬如 循环流只是在判断合法不合法。
真正从 S->T的流量是 T到S的边的反向边。因为所有的流量都是T到S流的。
最后还需要退流。保证图中的流量在合法的时候最小。
考虑 普通的最大流怎么做 可以发现直接求的是最大的数量 和最小的数量不同。
不难将题意转换成求最大能够去掉的棋子数。
判断合法不合法很容易。考虑先在图中满足所有棋子都在图中。
考虑建图:不难建出 源点向没一行都建出总-限制的流量 对列也是如此。
没有坏掉的格子建边。求出最多能够去掉的棋子个数即可。
可以发现 满足题中的要求 且 求出了去掉棋子最多的个数 总数减一下即可。这也是通常说的正难则反。
code:上下界最小流代码。
const int MAXN=210;
int n,m,k,len=1,SS,TT,S,T,l,r;
int x[MAXN],y[MAXN];
int a[MAXN][MAXN],d[MAXN],q[MAXN*MAXN],vis[MAXN],cur[MAXN];
int lin[MAXN],ver[MAXN*MAXN<<1],nex[MAXN*MAXN<<1],e[MAXN*MAXN<<1];
inline void add(int x,int y,int z)
{
ver[++len]=y;nex[len]=lin[x];lin[x]=len;e[len]=z;
ver[++len]=x;nex[len]=lin[y];lin[y]=len;e[len]=0;
}
inline void add(int x,int y,int l,int r)
{
d[x]-=l;d[y]+=l;
add(x,y,r-l);
}
inline int bfs(int s1,int s2)
{
rep(1,TT,i)vis[i]=0,cur[i]=lin[i];
l=r=0;q[++r]=s1;vis[s1]=1;
while(++l<=r)
{
int x=q[l];
go(x)
{
if(vis[tn]||!e[i])continue;
vis[tn]=vis[x]+1;
q[++r]=tn;
if(tn==s2)return 1;
}
}
return 0;
}
inline int dinic(int x,int s2,int flow)
{
if(x==s2)return flow;
int k=0,res=flow;
for(int i=cur[x];i&&res;i=nex[i])
{
cur[x]=i;int tn=ver[i];
if(vis[tn]==vis[x]+1&&e[i])
{
k=dinic(tn,s2,min(e[i],flow));
if(!k){vis[tn]=0;continue;}
e[i]-=k;e[i^1]+=k;res-=k;
}
}
return flow-res;
}
int main()
{
freopen("chessman.in","r",stdin);
freopen("chessman.out","w",stdout);
get(n);get(m);get(k);
S=n+m+1;T=S+1;
rep(1,n,i)get(x[i]),add(S,i,x[i],INF);
rep(1,m,j)get(y[j]),add(j+n,T,y[j],INF);
rep(1,k,i)
{
int x,y;
get(x);get(y);
a[x][y]=1;
}
rep(1,n,i)rep(1,m,j)
{
if(a[i][j])continue;
add(i,j+n,0,1);
}
SS=T+1;TT=SS+1;
int res=0;
rep(1,T,i)
{
if(d[i]>0)add(SS,i,d[i]),res+=d[i];
if(d[i]<0)add(i,TT,-d[i]);
}
int sum=0,flow=0;
add(T,S,INF);
while(bfs(SS,TT))while((flow=dinic(SS,TT,INF)))sum+=flow;
if(sum!=res){puts("No Solution");return 0;}
sum=0;res=e[len];e[len^1]=0;
while(bfs(T,S))while((flow=dinic(T,S,INF)))sum+=flow;
put(res-sum);return 0;
}