「WF2011」Chips Challenge 题解(全网最详细清晰)
思路
这道题是一道最小费用最大流
首先,遇到这种题,我们可以先把每一行与每一列开成点,然后通过行与列间的连线关系来表示点的删除与没有被删除的关系
正男则反,先假设每个能被选的点都被选了,那么我们接下来的目标是求出在满足两个条件下最小的删去边的个数
我们先想一想源点向行连边的信息
边权肯定是0,那流量 \(f\) 呢?
我认为这里的流量 \(f\) 代表的是被做出了决策(选或不选)的点的个数
当然,为'/'的是不能选的(因为已经考虑完了,不考虑这一部分),来考虑'C'(虽说这是必须选,但我们还没有对这一部分进行抉择,且这一部分也是会实打实的增加行上点的个数,所以要考虑)和'.'
我们要对这些点做出抉择,那么也就是要对不是'/'的点个数个点进行讨论,设为 \(rx_i\)
所以就是 \((s,i,rx_i,0)\)
那么从列 \(j\) 到 \(t\) 呢?
也是要对这一列非'/'的个数个点进行抉择,所以类似地:
\((j,t,ry_j,0)\)
最重要的是接下来的:
保证第 \(i\) 行与第 \(i\) 列被选的个数一样
但是别忘了,我们还有个条件:第 \(i\) 行的零件数目不能超过总的零件数目的 \(\frac{A}{B}\)
这时,我们可以枚举一下每行最多的零件个数 \(v\)
回到刚刚的主题,由于我们开始钦定了所有点都选,那么我们可以连一条 \((i,i+n,v,0)\) 的边
实际流动的时候,若这条边流动了 \(x\) 的流量,那么说明第 \(i\) 行与第 \(i\) 列有 \(x\) 个共同的零件
那主播主播,你这样限制第 \(i\) 行与第 \(i\) 列要相同,那只有 \(x\) 个位置的零件是确定要放的,那第 \(i\) 行和第 \(i\) 列剩下还有一些位置没有进行抉择啊?
所说这十分地白痴,但是我实际中却遇到了这个问题
不是,剩下的点肯定是不放啊!!!!!!!
那问题来了,让一个抉择是不放 总要提供一个通道吧
没错,现在来解决这个问题
假设有个点 \((i,j)\) 可以被删除(也就是为'.'的点)
现在我们的目标是让 \(i\) 行分出一的流量(也就是把一个抉择变成不放置),然后还要让第 \(j\) 列多流来一个流量(代表这一列中有一个位置的抉择是不放)
我们还要经过这条边会产生1的权值,因为我们要统计最小删除的点数
那这就十分清晰明了了,直接连一条 \((i,j+n,1,1)\)
最后一个问题,判断合法
我们当然要让每一个需要抉择的点做出抉择,所以也就是要让总流量为所有非'/'的点的数量 \(sum\)
于是愉快地跑个最小费用最大流
当然还要判断 \(v\)(不记得是啥的看上文)是否满足不能超过总的零件( \(sum\) - 删去点数量)数目的 \(\frac{A}{B}\)
对于所有合法的 \(v\) 的情况,取个零件个数的 \(max\) 再减去必须选的点的个数就是我们要求的答案(新增点个数)了
这道题有点水平,我觉得我是全网最清晰题解
Code
#include<bits/stdc++.h>
using namespace std;
int n,A,B,sum,need,s,t;
int cnt=1,head[510],tx[510],ty[510],now[510],cost,dis[510],vis[510];
struct no{
int from,to,nxt,c,w;
}e[20010],cpy[1010];
inline void add(int u,int v,int c,int w){
e[++cnt]={u,v,head[u],c,w};
head[u]=cnt;
e[++cnt]={v,u,head[v],0,-w};
head[v]=cnt;
}
char mp[510][510];
inline int bfs(){
memset(dis,0x3f,sizeof dis);
memset(vis,0,sizeof vis);
memcpy(now,head,sizeof now);
queue<int>q;
q.push(s);
dis[s]=0;
vis[s]=1;
while(q.size()){
int u=q.front();
q.pop();//cout<<u<<'\n';
vis[u]=0;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to,w=e[i].w;
if(e[i].c>0 and dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
if(!vis[v])q.push(v),vis[v]=1;
}
}
}
return dis[t]!=0x3f3f3f3f;
}
inline int dfs(int u,int flow){
if(u==t or !flow)return flow;
int res=0;
vis[u]=1;
for(int i=now[u];i and flow;i=e[i].nxt){
int v=e[i].to;
now[u]=i;
if(!vis[v] and e[i].c>0 and dis[u]+e[i].w==dis[v]){
int f=dfs(v,min(flow,e[i].c));
cost+=f*e[i].w;
res+=f;
flow-=f;
e[i].c-=f;
e[i^1].c+=f;
}
}
vis[u]=0;
return res;
}
inline int dick(){
int res=0;
while(bfs()){
memset(vis,0,sizeof vis);
res+=dfs(s,0x3f3f3f3f);
}return res;
}
inline void solve(int dyfucgggggggggggggggggge7iytyfgiycgbewyeiuvvybvueeuyreufgtgyfhreufgewrioey){
if(n==A and A==B and n==0){
exit(0);
}
cout<<"Case "<<dyfucgggggggggggggggggge7iytyfgiycgbewyeiuvvybvueeuyreufgtgyfhreufgewrioey<<": ";
memset(tx,0,sizeof tx);
memset(ty,0,sizeof ty);
sum=0,need=0;s=2*n+1,t=s+1;
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){
char ch;
cin>>ch;
if(ch!='/')tx[i]++,ty[j]++,sum++,need+=(ch=='C');
mp[i][j]=ch;
}int ans=-1;
for(int v=0;v<=n;v++){
memset(head,0,sizeof head);
cnt=1;
for(int i=1;i<=n;i++){
add(s,i,tx[i],0);
add(i+n,t,ty[i],0);
//cout<<ty[i]<<'\n';
add(i,i+n,v,0);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(mp[i][j]=='.')add(i,j+n,1,1);
}
}
cost=0;
int flow=dick();
//cout<<flow<<'\n';
if(flow==sum and (sum-cost)*A>=v*B){
ans=max(ans,sum-cost);
}
}
if(ans==-1)cout<<"impossible\n";
else cout<<ans-need<<'\n';
}
main(){
cin.tie(0)->ios::sync_with_stdio(0);
int igqfyugyftydfewytgbuyrfu7yfhjhuaajhbnhdnhhsdhbgsr5ffffffffffffffffffffffffffffffffffffffffffffffffff=0;
while(cin>>n>>A>>B)igqfyugyftydfewytgbuyrfu7yfhjhuaajhbnhdnhhsdhbgsr5ffffffffffffffffffffffffffffffffffffffffffffffffff++,solve(igqfyugyftydfewytgbuyrfu7yfhjhuaajhbnhdnhhsdhbgsr5ffffffffffffffffffffffffffffffffffffffffffffffffff);
return 0;
}

浙公网安备 33010602011771号