题意

给出一个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)

当然这个算法很慢,我们可以利用这张图的特性,手动消一些正权圈,细节看代码.

我可能还需要学习一个有上下界的费用流

  1. #include<cstdio>
  2. #include<cmath>
  3. #include<cstring>
  4. #include<algorithm>
  5. using namespace std;
  6. const int maxn=85,maxm=100005;
  7. struct edge{
  8. int to,next,w,cost;
  9. }lst[maxm];int len=0,first[maxn],_first[maxn];
  10. void addedge(int a,int b,int w,int cost){
  11. lst[len].to=b;lst[len].next=first[a];lst[len].w=w;lst[len].cost=cost;first[a]=len++;
  12. lst[len].to=a;lst[len].next=first[b];lst[len].w=0;lst[len].cost=-cost;first[b]=len++;
  13. }
  14. int ans=0,maxans=-1;
  15. int totflow[maxn];
  16. int pos[maxn][maxn];
  17. void Add(int a,int b,int lo,int hi,int cost){
  18. pos[a][b]=len;
  19. ans+=lo*cost;totflow[a]-=lo;totflow[b]+=lo;
  20. addedge(a,b,hi-lo,cost);
  21. }
  22. int n,A,B;
  23. char str[maxn][maxn];
  24. int s,t,q[maxn],dis[maxn],vis[maxm],prt[maxn],fr[maxn],head,tail,T;
  25. bool bfs(){
  26. head=tail=0;vis[s]=++T;dis[s]=1;q[tail++]=s;
  27. while(head!=tail){
  28. int x=q[head++];
  29. for(int pt=first[x];pt!=-1;pt=lst[pt].next){
  30. if(lst[pt].w&&vis[lst[pt].to]!=T){
  31. vis[lst[pt].to]=T;dis[lst[pt].to]=dis[x]+1;q[tail++]=lst[pt].to;
  32. }
  33. }
  34. }
  35. if(vis[t]==T)memcpy(_first,first,sizeof(first));
  36. return vis[t]==T;
  37. }
  38. int dfs(int x,int lim){
  39. if(x==t)return lim;
  40. int flow=0,a;
  41. for(int pt=_first[x];pt!=-1;pt=lst[pt].next){
  42. _first[x]=pt;
  43. if(lst[pt].w&&dis[lst[pt].to]==dis[x]+1&&(a=dfs(lst[pt].to,min(lst[pt].w,lim-flow)))){
  44. lst[pt].w-=a;lst[pt^1].w+=a;flow+=a;ans+=a*lst[pt].cost;
  45. if(flow==lim)return flow;
  46. }
  47. }
  48. return flow;
  49. }
  50. int dinic(){
  51. int flow=0,x;
  52. while(bfs()){
  53. while(x=dfs(s,0x3f3f3f3f)){
  54. flow+=x;
  55. }
  56. }
  57. return flow;
  58. }
  59. void del(int x){
  60. for(int pt=first[x];pt!=-1;pt=lst[pt].next)lst[pt].w=lst[pt^1].w=0;
  61. }
  62. bool inq[maxn];
  63. int f[maxn];
  64. bool spfa(){
  65. for(int i=1;i<=2*n;++i)inq[i]=false;
  66. head=tail=0;++T;
  67. for(int i=1;i<=n;++i){
  68. dis[i]=0;q[tail++]=i;vis[i]=T;inq[i]=true;prt[i]=-1;
  69. f[i]=1;
  70. }
  71. bool flag=false;
  72. while(head!=tail){
  73. int x=q[head++];if(head==maxn)head=0;inq[x]=false;
  74. for(int pt=first[x];pt!=-1;pt=lst[pt].next){
  75. if(f[x]>2*n){
  76. flag=true;break;
  77. }
  78. if(lst[pt].w==0)continue;int y=lst[pt].to;
  79. if(vis[y]!=T||dis[y]<dis[x]+lst[pt].cost){
  80. vis[y]=T;
  81. dis[y]=dis[x]+lst[pt].cost;f[y]=f[x]+1;
  82. prt[y]=pt;
  83. if(!inq[y]){
  84. inq[y]=true;q[tail++]=y;
  85. if(tail==maxn)tail=0;
  86. }
  87. }
  88. }
  89. }
  90. if(flag){
  91. for(int i=1;i<=2*n;++i){
  92. if(f[i]>2*n){
  93. vis[i]=++T;
  94. int pos=i;
  95. for(int pt=prt[i];vis[lst[pt^1].to]!=T;pt=prt[lst[pt^1].to]){
  96. vis[lst[pt^1].to]=T;pos=lst[pt^1].to;
  97. }
  98. ++T;
  99. for(int pt=prt[pos];vis[pt]!=T;pt=prt[lst[pt^1].to]){
  100. ans+=lst[pt].cost;lst[pt].w--;lst[pt^1].w++;vis[pt]=T;
  101. }
  102. break;
  103. }
  104. }
  105. return true;
  106. }else
  107. return false;
  108. }
  109. void addflow(int pt){
  110. lst[pt].w--;lst[pt^1].w++;ans+=lst[pt].cost;
  111. }
  112. bool maxcost(){
  113. int tmpsum=0;
  114. s=0;t=2*n+1;
  115. for(int i=1;i<=n*2;++i){
  116. if(totflow[i]>0){
  117. addedge(s,i,totflow[i],0);
  118. tmpsum+=totflow[i];
  119. }else{
  120. addedge(i,t,-totflow[i],0);
  121. }
  122. }
  123. if(dinic()!=tmpsum)return false;
  124. del(s);del(t);
  125. for(int i=1;i<=n;++i){
  126. for(int j=1;j<=n;++j){
  127. if(pos[i][n+j]==-1||pos[j][n+i]==-1||pos[n+i][i]==-1||pos[n+j][j]==-1)continue;
  128. 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){
  129. addflow(pos[i][n+j]);addflow(pos[j][n+i]);addflow(pos[n+i][i]);addflow(pos[n+j][j]);
  130. }
  131. }
  132. }
  133. while(spfa());
  134. return true;
  135. }
  136. bool check(int uplim){
  137. ans=0;memset(first,-1,sizeof(first));len=0;
  138. memset(pos,-1,sizeof(pos));
  139. for(int i=1;i<=n*2;++i)totflow[i]=0;
  140. for(int i=1;i<=n;++i)Add(n+i,i,0,uplim,0);
  141. for(int i=1;i<=n;++i){
  142. for(int j=1;j<=n;++j){
  143. if(str[i][j]=='C'){
  144. Add(i,n+j,1,1,1);
  145. }else if(str[i][j]=='.'){
  146. Add(i,n+j,0,1,1);
  147. }
  148. }
  149. }
  150. if(maxcost()){
  151. int lim2=ceil(uplim/double(A)*double(B));
  152. if(ans>=lim2&&ans>=maxans)maxans=ans;
  153. }
  154. }
  155. int main(){
  156. int tests=0;
  157. while(scanf("%d%d%d",&n,&A,&B),n!=0){
  158. maxans=-1;ans=0;
  159. ++tests;
  160. for(int i=1;i<=n;++i)scanf("%s",str[i]+1);
  161. int init=0,l=0,r=0;
  162. int sum=0;
  163. for(int i=1;i<=n;++i){
  164. for(int j=1;j<=n;++j){
  165. if(str[i][j]=='C'){
  166. init++;sum++;
  167. }else if(str[i][j]=='.')sum++;
  168. }
  169. }
  170. if(1.0/n>A/double(B)){
  171. if(init!=0)printf("Case %d: impossible\n",tests);
  172. else printf("Case %d: 0\n",tests);
  173. continue;
  174. }
  175. double bound=min((int)(sum*1.0*A/B),n);
  176. for(int uplim=bound;uplim>=0;--uplim){
  177. check(uplim);if(maxans!=-1)break;
  178. }
  179. if(maxans!=-1)printf("Case %d: %d\n",tests,maxans-init);
  180. else printf("Case %d: impossible\n",tests);
  181. }
  182. return 0;
  183. }

bzoj3961[WF2011]Chips Challenge的更多相关文章

  1. 【BZOJ 2673】[Wf2011]Chips Challenge

    题目大意: 传送门 $n*n$的棋盘,有一些位置可以放棋子,有一些已经放了棋子,有一些什么都没有,也不能放,要求放置以后满足:第i行和第i列的棋子数相同,同时每行的棋子数占总数比例小于$\frac{A ...

  2. Bzoj2673 3961: [WF2011]Chips Challenge 费用流

    国际惯例题面:如果我们枚举放几个零件的话,第二个限制很容易解决,但是第一个怎么办?(好的,这么建图不可做)考虑我们枚举每行每列最多放几个零件t,然后计算零件总数sum.这样如果可行的话,则有t*B&l ...

  3. BZOJ2673 [Wf2011]Chips Challenge 费用流 zkw费用流 网络流

    https://darkbzoj.cf/problem/2673 有一个芯片,芯片上有N*N(1≤N≤40)个插槽,可以在里面装零件. 有些插槽不能装零件,有些插槽必须装零件,剩下的插槽随意. 要求装 ...

  4. [Wf2011]Chips Challenge

    两个条件都不太好处理 每行放置的个数实际很小,枚举最多放x 但还是不好放 考虑所有位置先都放上,然后删除最少使得合法 为了凑所有的位置都考虑到,把它当最大流 但是删除最少,所以最小费用 行列相关,左行 ...

  5. bzoj 3961: [WF2011]Chips Challenge【最小费用最大流】

    参考:https://blog.csdn.net/Quack_quack/article/details/50554032 神建图系列 首先把问题转为全填上,最少扣下来几个能符合条件 先考虑第2个条件 ...

  6. [2011WorldFinal]Chips Challenge[流量平衡]

    Chips Challenge Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) ...

  7. 【UVALive - 5131】Chips Challenge(上下界循环费用流)

    Description A prominent microprocessor company has enlisted your help to lay out some interchangeabl ...

  8. 解题:BZOJ 2673 World Final 2011 Chips Challenge

    题面 数据范围看起来很像网络流诶(滚那 因为限制多而且强,数据范围也不大,我们考虑不直接求答案,而是转化为判定问题 可以发现第二个限制相对好满足,我们直接枚举这个限制就可以.具体来说是枚举所有行中的最 ...

  9. 【题解】uva1104 chips challenge

    原题传送门 题目分析 给定一张n*n的芯片. '.'表示该格子可以放一个零件. 'C'表示该格子已经放了一个零件(不能拆下). '/'表示该格子不能放零件. 要求在芯片的现有基础上,放置尽可能多的零件 ...

随机推荐

  1. week8课上实践

    课上练习. 第一题: 参考 http://www.cnblogs.com/rocedu/p/6766748.html#SECCLA 在Linux下完成"求命令行传入整数参数的和" ...

  2. 简单的Slony-I设置实例

    磨砺技术珠矶,践行数据之道,追求卓越价值 回到上一级页面: PostgreSQL集群方案相关索引页     回到顶级页面:PostgreSQL索引页 参考如下链接: http://lets.postg ...

  3. virsh常用维护命令

    virsh常用命令 一些常用命令参数 [root@kvm-server ~]# virsh --help                                     #查看命令帮忙 [ro ...

  4. 读懂UML类图

    平时阅读一些远吗分析类文章或是设计应用架构时没少与UML类图打交道.实际上,UML类图中最常用到的元素五分钟就能掌握,下面赶紧来一起认识一下它吧: 一.类的属性的表示方式 在UML类图中,类使用包含类 ...

  5. Maven学习(一)-----Maven安装配置总结

    想要安装 Apache Maven 在Windows 系统上, 需要下载 Maven 的 zip 文件,并将其解压到你想安装的目录,并配置 Windows 环境变量. 所需工具 : JDK 1.8 M ...

  6. LUIS 语义识别API调用方法

    本例使用itchat获取微信文字消息,发送给LUIS返回识别消息,再将返回消息格式化后通过微信发回 关于itchat的使用参考我的另外一篇随笔itchat个人练习 语音与文本图灵测试例程 # -*- ...

  7. 【python 2.7】python读取json数据存入MySQL

    同上一篇,只是适配 CentOS+ python 2.7 #python 2.7 # -*- coding:utf-8 -*- __author__ = 'BH8ANK' import json im ...

  8. Hackerank-Array-NewYearChaos

    题目背景描述 新年第一天,N 个人排队坐过山车.每个人穿有带编号的衣服 \([1, 2, 3, ...]\). 因为排队时间太久,有人发现给前面相邻的人喂一颗糖,就可以和他交换位置,而每人手里只有两颗 ...

  9. mysql优化建议21条

    转自: http://blog.csdn.net/waferleo/article/details/7179009 今 天,数据库的操作越来越成为整个应用的性能瓶颈了,这点对于Web应用尤其明显.关于 ...

  10. mysql数据库工具

    1.navicat12 中文版及破解 链接:https://pan.baidu.com/s/1TH8m6lduHJybUGhmjFPIAA 提取码:kwcd 2.旧版本mysql-front(连接可选 ...