UVA1104 Chips Challenge(费用流)
神仙费用流题,理解了一下午,故写此篇题解以作纪念。
题意
有一个 \(N\times N\) 的棋盘,有些格子不能放棋子,有些格子必须放棋子,剩下的格子随意。要求放好棋子之后满足:
- 第 \(i\) 行和第 \(i\) 列的棋子数相同。\((1\le i\le n)\)
- 任何一行的棋子数不能超过总的棋子数目的 \(\frac{A}{B}\) 。
求最多可以另外放多少个棋子。
做法
我们考虑先把整张图放满,再删去一些点。
首先可以想到的是用点 \(x_i\) 表示第 \(i\) 行,点 \(y_i\) 表示第 \(i\) 列,源点向所有 \(x_i\) 连边,所有 \(y_i\) 向汇点连边。
由于第二条限制与总棋子数有关,难以直接计算,可以枚举限制(即最多每行可以放的棋子数)后求最大的总棋子数判断合法性。
那么难点在于如何满足第一个限制。一个并不容易想到的思路是在最大流的基础上增加费用,用流量判断合法,用费用统计答案。
这里先给出建图方法,再逐一解释:
设 \(totx_i,toty_i\) 为第 \(i\) 行/列全部放满能放的棋子数,\(limit\) 为枚举的限制。
- \(S\) 向 \(x_i\) 连边,容量为 \(totx_i\),费用为 \(0\),\(y_i\) 向 \(T\) 连边,容量为 \(toty_i\),费用为 \(0\)。
- \(x_i\) 向 \(y_i\) 连边,容量为 \(limit\),费用为 \(0\)。
- 对于每个可以选择放不放的点 \((i,j)\),\(x_i\) 向 \(y_j\) 连边,容量为 \(1\),费用为 \(1\)。若这条边有流,则代表移走点 \((i,j)\) 上的棋子。
对于该图跑最小费用最大流,最小费用即为最少删去的点数。
方案合法当且仅当所有直接与 \(S,T\) 相连的边满流,且剩下的棋子数 \(\ge \frac{B}{A}\times limit\)。
接下来解释一下这样建图为什么能保证满足限制一。
考虑我们建的边的实际意义。
从点 \(x_i\) 流出的流量,流向费用为 \(1\) 的边则代表该点被删除,那么所有没被删除的点都流向了 \(y_i\)。那么 \(x_i\rightarrow y_i\) 这条边的流量即代表第 \(i\) 行保留的棋子数。
同理,\(x_i\rightarrow y_i\) 的流量也表示第 \(i\) 列保留的棋子数。所以第 \(i\) 行和第 \(i\) 列能够保证棋子数相等,且不会超过 \(limit\)。
至于其他限制都在建图过程中直观体现,这里不再一一赘述。
AC code
#include<bits/stdc++.h>
#define il inline
using namespace std;
il int read()
{
int xr=0,F=1;char cr=getchar();
while(cr<'0'||cr>'9') {if(cr=='-') F=-1;cr=getchar();}
while(cr>='0'&&cr<='9')
xr=(xr<<3)+(xr<<1)+(cr^48),cr=getchar();
return xr*F;
}
const int N=5005,inf=1e9;
int n,a,b,s,t;
char mp[N][N];
struct edge{
int nxt,to,w,c;
}e[N<<1];
int head[N],cnt=1;
void add(int u,int v,int w,int c){
//cout<<u<<" "<<v<<" "<<w<<endl;
e[++cnt]={head[u],v,w,c};head[u]=cnt;
e[++cnt]={head[v],u,0,-c};head[v]=cnt;
}
int dis[N],now[N],in[N];
bool spfa()
{
queue<int> q;
for(int i=s;i<=t;i++) now[i]=head[i],dis[i]=inf;
dis[s]=0,in[s]=1; q.push(s);
while(!q.empty())
{
int u=q.front();in[u]=0,q.pop();
for(int i=head[u];i;i=e[i].nxt)
{
int v=e[i].to,w=e[i].w;
if(w&&dis[v]>dis[u]+e[i].c)
{
dis[v]=dis[u]+e[i].c;
if(!in[v]) in[v]=1,q.push(v);
}
}
}
return dis[t]!=inf;
}
int dfs(int u,int sum)
{
if(u==t) return sum;
int res=0;in[u]=1;
for(int &i=now[u];i&∑i=e[i].nxt)
{
int v=e[i].to,w=e[i].w;
if(!w||in[v]||dis[v]!=dis[u]+e[i].c) continue;
int k=dfs(v,min(sum,w));
e[i].w-=k,e[i^1].w+=k;
res+=k,sum-=k;
}
if(sum) dis[u]=inf;
in[u]=0;return res;
}
il void clear()
{
memset(e,0,sizeof(e)),cnt=1;
memset(head,0,sizeof(head));
}
void build(int limit)
{
for(int i=1;i<=n;i++)
{
add(i,i+n,limit,0);
int tot=0;
for(int j=1;j<=n;j++) if(mp[i][j]!='/') tot++;
add(s,i,tot,0);tot=0;
for(int j=1;j<=n;j++) if(mp[j][i]!='/') tot++;
add(i+n,t,tot,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);
}
}
}
int main()
{
int cas=0;
while("qwq")
{
cas++;
n=read(),a=read(),b=read();
if(!n) return 0;
s=0,t=2*n+1;int mx=-1,cntc=0,tot=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
cin>>mp[i][j];
if(mp[i][j]=='C') cntc++;
if(mp[i][j]!='/') tot++;
}
}
for(int i=0;i<=n;i++)
{
clear();
build(i);
int ans=0,flow=0;
while(spfa())
{
int k=dfs(s,inf);
ans+=dis[t]*k,flow+=k;
}
if(flow==tot&&i*b<=(tot-ans)*a) mx=max(mx,tot-ans-cntc);
}
printf("Case %d: ",cas);
if(mx==-1) printf("impossible\n");
else printf("%d\n",mx);
}
return 0;
}
UVA1104 Chips Challenge(费用流)的更多相关文章
- Bzoj2673 3961: [WF2011]Chips Challenge 费用流
国际惯例题面:如果我们枚举放几个零件的话,第二个限制很容易解决,但是第一个怎么办?(好的,这么建图不可做)考虑我们枚举每行每列最多放几个零件t,然后计算零件总数sum.这样如果可行的话,则有t*B&l ...
- BZOJ2673 [Wf2011]Chips Challenge 费用流 zkw费用流 网络流
https://darkbzoj.cf/problem/2673 有一个芯片,芯片上有N*N(1≤N≤40)个插槽,可以在里面装零件. 有些插槽不能装零件,有些插槽必须装零件,剩下的插槽随意. 要求装 ...
- 【题解】uva1104 chips challenge
原题传送门 题目分析 给定一张n*n的芯片. '.'表示该格子可以放一个零件. 'C'表示该格子已经放了一个零件(不能拆下). '/'表示该格子不能放零件. 要求在芯片的现有基础上,放置尽可能多的零件 ...
- UVA1104 Chips Challenge
一.题目 有一个 \(n\times n\) 的矩阵,每个元素可能是 ..C./ 的其中一种,分别表示可以放置芯片.已经放置了芯片.不能放置芯片,你可以分别决定是否可以放置芯片的位置放置芯片. 最后需 ...
- 【UVALive - 5131】Chips Challenge(上下界循环费用流)
Description A prominent microprocessor company has enlisted your help to lay out some interchangeabl ...
- bzoj 3961: [WF2011]Chips Challenge【最小费用最大流】
参考:https://blog.csdn.net/Quack_quack/article/details/50554032 神建图系列 首先把问题转为全填上,最少扣下来几个能符合条件 先考虑第2个条件 ...
- 【BZOJ3502/2288】PA2012 Tanie linie/【POJ Challenge】生日礼物 堆+链表(模拟费用流)
[BZOJ3502]PA2012 Tanie linie Description n个数字,求不相交的总和最大的最多k个连续子序列. 1<= k<= N<= 1000000. Sam ...
- hdu-5988 Coding Contest(费用流)
题目链接: Coding Contest Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Ot ...
- POJ2195 Going Home[费用流|二分图最大权匹配]
Going Home Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 22088 Accepted: 11155 Desc ...
- BZOJ3130: [Sdoi2013]费用流[最大流 实数二分]
3130: [Sdoi2013]费用流 Time Limit: 10 Sec Memory Limit: 128 MBSec Special JudgeSubmit: 960 Solved: 5 ...
随机推荐
- 微信小程序常用的view、text、button、image组件
[黑马程序员前端微信小程序开发教程,微信小程序从基础到发布全流程_企业级商城实战(含uni-app项目多端部署)] https://www.bilibili.com/video/BV1834y1676 ...
- 2023-07-08:RabbitMQ如何做到消息不丢失?
2023-07-08:RabbitMQ如何做到消息不丢失? 答案2023-07-08: 1.持久化 发送消息时设置delivery_mode属性为2,使消息被持久化保存到磁盘,即使RabbitMQ服务 ...
- 2023-07-10:Kafka如何做到消息不丢失?
2023-07-10:Kafka如何做到消息不丢失? 答案2023-07-10: Kafka采用多种机制来确保消息的不丢失,其中包括副本机制.ISR(In-Sync Replicas)机制以及ACK机 ...
- 前端uni-app自定义精美全端复制文本插件,支持全端文本复制插件 可设置复制按钮颜色
随着技术的发展,开发的复杂度也越来越高,传统开发方式将一个系统做成了整块应用,经常出现的情况就是一个小小的改动或者一个小功能的增加可能会引起整体逻辑的修改,造成牵一发而动全身. 通过组件化开发,可以有 ...
- Windows10 下 Neo4j1.5.8 安装教程
前言 Neo4j 是一个高性能的.NOSQL 图形数据库,它将结构化数据存储在网络上而不是表中.基于磁盘的.具备完全的事务特性的 Java 持久化引擎,这里就不把他和常用关系型数据库做对比了.因为篇幅 ...
- 关于quartus II的导入以前的工程,QSF文件出现的错误的解决方案。
在有时候打开以前的工程,或者别人做好的例程会遇到一些报错信息.具体报错信息如下: 报错信息语句行: 在文件QSF文件中有几行出错,显示错误读取,即不能打开工程.打开文件发现该几行的PIN 使能信号处于 ...
- Vue错误:Cannot read properties of undefined (reading '$router')
解决方案 这是由于this的指向有问题,我们只需要重新声明一下this就可以重新调用了
- 【linux】你需要以 root 身份执行此命令
1.设置root用户的密码: sudo passwd root 2.切换到root用户权限 su 3.切换回个人用户权限 exit
- 小白终于解决了在学习Go中不知道Makefile是什么的难题
如何在Go中使用Makefile 1.Makefile是什么 Makefile是一种构建工具,用于在项目中定义和执行一系列命令.它通常包含了一些规则和目标,用于编译.测试.运行和清理项目. 2.Mak ...
- 保护个人数据安全,使用luks加密硬盘分区
create:2023-01-24 17:44:44 准备工作 新硬盘4T,无数据.在root用户或sudo状态下执行. 首先创建分区表,由于mbr最大支持只有2T,因此分区表创建为gpt格式. 然后 ...