bzoj3961[WF2011]Chips Challenge
题意
给出一个n*n的网格,有些格子必须染成黑色,有些格子必须染成白色,其他格子可以染成黑色或者白色.要求最后第i行的黑格子数目等于第i列的黑格子数目,且某一行/列的格子数目不能超过格子总数的A/B.
(把某个格子染黑等价于"在这个格子放一个芯片")
n<=40
分析
假设一共用了X个芯片(包括'C'和'.'两种情况下放的),那么每行每列最多放的芯片个数Y=X*A/B可以算出来.发现不同的Y值最多有40个,我们可以考虑枚举每个Y值,Y值确定之后X有一个下界,我们考虑此时最多放下的芯片个数能否达到这个下界即可.
建出2n个点分别代表n行n列,第i行向第j列连一条边.
如果(i,j)是'C',那么这条边的上下界均为1.
如果(i,j)是'.',那么这条边的上下界为[0,1]
如果(i,j)是'',那么上下界均为0(相当于没有边).
然后我们从第i列到第i行连一条下界为0上界为Y的边.
这张网络上一个满足流量平衡的流就对应一个合法的方案.我们要最大化代表格子的n*n条边里有流量的边数.不妨把这n*n条边的费用都设为1,我们现在只需要找出一个满足流量上下界限制且费用最大的循环流.
接下来我的做法就纯属乱搞了,应该可以换成更加有理有据的上下界费用流
首先考虑满足流量上下界限制.套用上下界网络流中循环可行流那一套理论即可.
现在跑出来的可行流不一定是费用最大的,残量网络里可能有正权圈.所以...我们暴力跑spfa,每次增广一个残量网络上的正权圈,直到不存在正权圈,就找到了最大费用的可行流...(我也不知道这为什么是对的,求证明或证伪,不过它确实能过23333)
当然这个算法很慢,我们可以利用这张图的特性,手动消一些正权圈,细节看代码.
我可能还需要学习一个有上下界的费用流
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=85,maxm=100005;
struct edge{
int to,next,w,cost;
}lst[maxm];int len=0,first[maxn],_first[maxn];
void addedge(int a,int b,int w,int cost){
lst[len].to=b;lst[len].next=first[a];lst[len].w=w;lst[len].cost=cost;first[a]=len++;
lst[len].to=a;lst[len].next=first[b];lst[len].w=0;lst[len].cost=-cost;first[b]=len++;
}
int ans=0,maxans=-1;
int totflow[maxn];
int pos[maxn][maxn];
void Add(int a,int b,int lo,int hi,int cost){
pos[a][b]=len;
ans+=lo*cost;totflow[a]-=lo;totflow[b]+=lo;
addedge(a,b,hi-lo,cost);
}
int n,A,B;
char str[maxn][maxn];
int s,t,q[maxn],dis[maxn],vis[maxm],prt[maxn],fr[maxn],head,tail,T;
bool bfs(){
head=tail=0;vis[s]=++T;dis[s]=1;q[tail++]=s;
while(head!=tail){
int x=q[head++];
for(int pt=first[x];pt!=-1;pt=lst[pt].next){
if(lst[pt].w&&vis[lst[pt].to]!=T){
vis[lst[pt].to]=T;dis[lst[pt].to]=dis[x]+1;q[tail++]=lst[pt].to;
}
}
}
if(vis[t]==T)memcpy(_first,first,sizeof(first));
return vis[t]==T;
}
int dfs(int x,int lim){
if(x==t)return lim;
int flow=0,a;
for(int pt=_first[x];pt!=-1;pt=lst[pt].next){
_first[x]=pt;
if(lst[pt].w&&dis[lst[pt].to]==dis[x]+1&&(a=dfs(lst[pt].to,min(lst[pt].w,lim-flow)))){
lst[pt].w-=a;lst[pt^1].w+=a;flow+=a;ans+=a*lst[pt].cost;
if(flow==lim)return flow;
}
}
return flow;
}
int dinic(){
int flow=0,x;
while(bfs()){
while(x=dfs(s,0x3f3f3f3f)){
flow+=x;
}
}
return flow;
}
void del(int x){
for(int pt=first[x];pt!=-1;pt=lst[pt].next)lst[pt].w=lst[pt^1].w=0;
}
bool inq[maxn];
int f[maxn];
bool spfa(){
for(int i=1;i<=2*n;++i)inq[i]=false;
head=tail=0;++T;
for(int i=1;i<=n;++i){
dis[i]=0;q[tail++]=i;vis[i]=T;inq[i]=true;prt[i]=-1;
f[i]=1;
}
bool flag=false;
while(head!=tail){
int x=q[head++];if(head==maxn)head=0;inq[x]=false;
for(int pt=first[x];pt!=-1;pt=lst[pt].next){
if(f[x]>2*n){
flag=true;break;
}
if(lst[pt].w==0)continue;int y=lst[pt].to;
if(vis[y]!=T||dis[y]<dis[x]+lst[pt].cost){
vis[y]=T;
dis[y]=dis[x]+lst[pt].cost;f[y]=f[x]+1;
prt[y]=pt;
if(!inq[y]){
inq[y]=true;q[tail++]=y;
if(tail==maxn)tail=0;
}
}
}
}
if(flag){
for(int i=1;i<=2*n;++i){
if(f[i]>2*n){
vis[i]=++T;
int pos=i;
for(int pt=prt[i];vis[lst[pt^1].to]!=T;pt=prt[lst[pt^1].to]){
vis[lst[pt^1].to]=T;pos=lst[pt^1].to;
}
++T;
for(int pt=prt[pos];vis[pt]!=T;pt=prt[lst[pt^1].to]){
ans+=lst[pt].cost;lst[pt].w--;lst[pt^1].w++;vis[pt]=T;
}
break;
}
}
return true;
}else
return false;
}
void addflow(int pt){
lst[pt].w--;lst[pt^1].w++;ans+=lst[pt].cost;
}
bool maxcost(){
int tmpsum=0;
s=0;t=2*n+1;
for(int i=1;i<=n*2;++i){
if(totflow[i]>0){
addedge(s,i,totflow[i],0);
tmpsum+=totflow[i];
}else{
addedge(i,t,-totflow[i],0);
}
}
if(dinic()!=tmpsum)return false;
del(s);del(t);
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
if(pos[i][n+j]==-1||pos[j][n+i]==-1||pos[n+i][i]==-1||pos[n+j][j]==-1)continue;
if(i!=j&&lst[pos[i][n+j]].w&&lst[pos[j][n+i]].w&&lst[pos[n+i][i]].w&&lst[pos[n+j][j]].w){
addflow(pos[i][n+j]);addflow(pos[j][n+i]);addflow(pos[n+i][i]);addflow(pos[n+j][j]);
}
}
}
while(spfa());
return true;
}
bool check(int uplim){
ans=0;memset(first,-1,sizeof(first));len=0;
memset(pos,-1,sizeof(pos));
for(int i=1;i<=n*2;++i)totflow[i]=0;
for(int i=1;i<=n;++i)Add(n+i,i,0,uplim,0);
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
if(str[i][j]=='C'){
Add(i,n+j,1,1,1);
}else if(str[i][j]=='.'){
Add(i,n+j,0,1,1);
}
}
}
if(maxcost()){
int lim2=ceil(uplim/double(A)*double(B));
if(ans>=lim2&&ans>=maxans)maxans=ans;
}
}
int main(){
int tests=0;
while(scanf("%d%d%d",&n,&A,&B),n!=0){
maxans=-1;ans=0;
++tests;
for(int i=1;i<=n;++i)scanf("%s",str[i]+1);
int init=0,l=0,r=0;
int sum=0;
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
if(str[i][j]=='C'){
init++;sum++;
}else if(str[i][j]=='.')sum++;
}
}
if(1.0/n>A/double(B)){
if(init!=0)printf("Case %d: impossible\n",tests);
else printf("Case %d: 0\n",tests);
continue;
}
double bound=min((int)(sum*1.0*A/B),n);
for(int uplim=bound;uplim>=0;--uplim){
check(uplim);if(maxans!=-1)break;
}
if(maxans!=-1)printf("Case %d: %d\n",tests,maxans-init);
else printf("Case %d: impossible\n",tests);
}
return 0;
}
bzoj3961[WF2011]Chips Challenge的更多相关文章
- 【BZOJ 2673】[Wf2011]Chips Challenge
题目大意: 传送门 $n*n$的棋盘,有一些位置可以放棋子,有一些已经放了棋子,有一些什么都没有,也不能放,要求放置以后满足:第i行和第i列的棋子数相同,同时每行的棋子数占总数比例小于$\frac{A ...
- 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)个插槽,可以在里面装零件. 有些插槽不能装零件,有些插槽必须装零件,剩下的插槽随意. 要求装 ...
- [Wf2011]Chips Challenge
两个条件都不太好处理 每行放置的个数实际很小,枚举最多放x 但还是不好放 考虑所有位置先都放上,然后删除最少使得合法 为了凑所有的位置都考虑到,把它当最大流 但是删除最少,所以最小费用 行列相关,左行 ...
- bzoj 3961: [WF2011]Chips Challenge【最小费用最大流】
参考:https://blog.csdn.net/Quack_quack/article/details/50554032 神建图系列 首先把问题转为全填上,最少扣下来几个能符合条件 先考虑第2个条件 ...
- [2011WorldFinal]Chips Challenge[流量平衡]
Chips Challenge Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) ...
- 【UVALive - 5131】Chips Challenge(上下界循环费用流)
Description A prominent microprocessor company has enlisted your help to lay out some interchangeabl ...
- 解题:BZOJ 2673 World Final 2011 Chips Challenge
题面 数据范围看起来很像网络流诶(滚那 因为限制多而且强,数据范围也不大,我们考虑不直接求答案,而是转化为判定问题 可以发现第二个限制相对好满足,我们直接枚举这个限制就可以.具体来说是枚举所有行中的最 ...
- 【题解】uva1104 chips challenge
原题传送门 题目分析 给定一张n*n的芯片. '.'表示该格子可以放一个零件. 'C'表示该格子已经放了一个零件(不能拆下). '/'表示该格子不能放零件. 要求在芯片的现有基础上,放置尽可能多的零件 ...
随机推荐
- I/O: std::ios_base::openmode
I/O: std::ios_base::openmode std::ios_base::openmode std::ios_base::in: 打开文件进行读操作,即读取文件中的数据 如果指定路径中 ...
- 1. oracle12C的安装
官方安装文档:https://docs.oracle.com/database/121/LTDQI/toc.htm#BHCCADGD 1.软件准备 oracle12c.zip 安装包 VMware 虚 ...
- angularjs 路由机制
前言 AngularJS路由主要有内置的ngRoute和一个基于ngRoute开发的第三方路由模块ui-router,内置的ngRoute有时满足开发需求,使用ui-router可以解决很多原生ngR ...
- textbox的验证
代码如下: textBox1.KeyDown += (a, b) => { if (b.KeyCode == Keys.Enter) { textBox2.Focus(); } }; textB ...
- katalon系列十七:报告&Katalon Analytics
一.邮件报告Suite执行完后,严格来说这个不算报告,只是邮件通知执行结果,具体设置请看katalon系列三 二.文件报告Suite执行完后,会在项目文件夹下/Report/Suite Name/ti ...
- 安装文件报错error while loading shared libraries: libssl.so.6
http://www.openssl.org/source/ 这里下载http://www.openssl.org/source/openssl-1.0.0r.tar.gz 安装命令为:tar -z ...
- 近中期3D编程研究目标
近几年一直在用业余时间研究3D编程,研究的中期目标是建立一个实用的开源3D编程框架.3D编程技术最直接的应用是开发游戏,所以3D编程框架也就是3D游戏开发框架.在我看来,游戏是否好玩的关键是能否为玩家 ...
- Memcached&PHP-Memcache安装配置
参考文档: memcache官网:https://memcached.org/ 参考:http://www.runoob.com/memcached/memcached-install.html 参考 ...
- 亚马逊与Twitter携手电子商务
亚马逊(Amazon)与Twitter开展了合作,允许用户以Twitter消息的形式将喜欢的商品发送到购物篮中.这些高科技企业正在想办法把社交媒体和电子商务融为一体. 这一功能旨在将Twitter转变 ...
- HTML页面模板代码
作者声明:本博客中所写的文章,都是博主自学过程的笔记,参考了很多的学习资料,学习资料和笔记会注明出处,所有的内容都以交流学习为主.有不正确的地方,欢迎批评指正 HTML页面模板代码 常用的页面模板 & ...