『ZOJ 3548』Chess Board

传送门戳这里n(*≧▽≦*)n

题目描述

Vallis Brook and Helen Heather like playing chess. Today they are not going to play chess buthave a competition on drawing a chess board. The chess board they used are a bit different from the ordinary one. The chess board consist of n rows and each row has m white square cells of the same size. Adjacent cells are seperated with a black border. There are also black borders on the edge of the chess board. Each border has the same width. The following figure shows how the chess board looks like. To make it like a chess board more, it is also constrained that the length of the cell should be no shorter than the width of the border, i.e. a ≥ b.


Now they are given a black-and-white image. They are going to make it a chess board as mentioned above. They both want to finish it faster than the other one.

In order to win the competition, Vallis managed to know how Helen would draw the chess board. Each time, Helen can draw a rectangle with one color and all the pixels in the rectangle will be painted with that color. He needs time T to draw one rectangle. In addition, he will only paint each pixel with the target color. That is to say, there will be no pixel to be painted multiple times with different colors. Because Vallis is busy drawing the chess board pixel by pixel, he ask you to help him calculate the minimum time for Helen to finish the job.

题目翻译(XJH版本)

又过去了若干年,XJH看淡一切,回归本源,决定还是继续写代码。

然而这时候的XJH已经把写代码的功夫忘差不多了,于是只能干最简单的活:给界面上放按钮。

但这不代表着XJH是一个没有追求的程序员,由于XJH的强迫症,他放的按钮,必须是工整,对称的。

假设XJH面对着一个R*C的界面,界面的每一个格子初始时候只有黑白两种颜色。

现在,XJH要在上面放r*c个按钮,每个按钮都是一个正方形,边长任意。

但是,由于XJH的强迫症,所有按钮和界面的边界,按钮两两之间,间隔必须是一样的!并且,这个间隔还要小于等于按钮的边长!

例如,如下图就是一个合法的放置。

 

7*7的格子上面,放了2*2个按钮。间隔1<=按钮边长2。

当按钮放好之后,XJH就要给按钮上色了,按钮要染成白色,其他位置要染成黑色。

每次染色,XJH可以选择任意一个矩形区域,一起染成白or黑。但是,某一个格子不能先被染了某种色,又被染成另一种颜色(也就是异色的染色矩形,不能相交)。

现在,已知每次染色消耗t的代价,放按钮没有代价,问:最少需要多少的代价,可以让XJH完成放按钮+染色的任务。

解题思路

首先,我们要来求每个按钮的边长即x,题目中要求按钮之间的距离相等,并且按钮和边的距离也要相等,那么我们可以对长度列一个方程,对宽度列一个方程。

首先对于横向的行,我们可以列出这样的方程:(c+1)*d+c*x=C   (d1代表按钮之间的距离)

然后对于纵向的列,我们可以列出这样的方程:(r+1)*d+r*x=R

我们联立两个方程,枚举x,判断求出来的d是不是整数,是否相等就可以求出满足条件的按钮的边长的值,注意x>=d并且d不能为0,这样我们就可以得到合法的最终的图像了。

然后,我们开始求解:

1) 对于每一按钮,如果按钮中有一个黑格子,那么我们不妨把整个按钮包含的格子都染成白的,这样,ans++;

2)对于按钮之外的区域,我们可以想到这样的一种朴素的做法:

我们把格子划成横向和竖向的两种长方形,如下图:

其中红色代表横向的长方形,蓝色代表竖向的长方形,那么显然,对于每一个格子,都会被一个横向的长方形和纵向的长方形覆盖,通俗的理解,如果选择横的,就不用选择竖的了(当然也可以选,只是对于这个格点来说没用了),反之亦然。那么我们将这两个长方形之间连一条边,处理完整个地图后,把所有的横向方形放在左侧,竖向方形放在右侧,我们就可以做二分图匹配了,其实就是选择最少的边,覆盖到所有的点。

重要的定理:二分图最大匹配=二分图最小点覆盖

但是我们看一看时间复杂度,二分度匹配的复杂度是n×m的,这样一定会TLE,因为最坏情况下,n和m都有可能接近2000*2000

我们就需要看看我们建立二分图的方法到底是不是最优的了:

比如,两个按钮的夹缝之间有一个位置上是白色的(绿色五角星qwq):

那么我们究竟应该怎么覆盖呢?从贪心的角度来说,我们不可能只覆盖那个小小的夹缝,我们一定选择把五角星所在的整个竖块覆盖,因为花费是相同的。那么对于横向的夹缝也是这样,经过这样的贪心之后,我们真正需要做二分图匹配的部分其实只有小小的一部分,如下图的黄点:

如果一个黄点内有一块白的,呢么我们把横竖的大方形之间连一条边,这样,我们再做二分图匹配,我们的复杂度就会降低到r×c,小了很多很多。

代码

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 using namespace std;
  6 long long ans=0,final=9999999999999LL;
  7 int h,w,n,m,t,cnt=0;
  8 bool map[2050][2050],col[2050][2050],vis[1000];
  9 int head[1000],ne[1000],to[1000],match[1000];
 10 inline void add(int f,int t){
 11     ne[++cnt]=head[f],head[f]=cnt,to[cnt]=t;
 12 }
 13 inline bool dfs(int x){
 14     for(register int i=head[x];i;i=ne[i]){
 15         if(!vis[to[i]]){
 16             vis[to[i]]=1;
 17             if(!match[to[i]]||dfs(match[to[i]])){
 18                 match[to[i]]=x;
 19                 return 1;
 20             }
 21         }
 22     }
 23     return 0;
 24 }
 25 int main(){
 26     while(~scanf("%d%d%d%d%d",&h,&w,&n,&m,&t)){
 27         cnt=0,final=9999999999999LL;
 28         memset(map,0,sizeof(map));
 29         memset(col,0,sizeof(col));
 30         memset(head,0,sizeof(head));
 31         memset(ne,0,sizeof(ne));
 32         memset(to,0,sizeof(to));
 33         memset(match,0,sizeof(match));
 34         for(register int i=1;i<=h;i++){
 35             char s[5000];
 36             scanf("%s",s+1);
 37             for(register int j=1;j<=w;j++){
 38                 map[i][j]=1^int(s[j]-'0');
 39             }
 40         }
 41         int x=1,flag=0;
 42         for(;x*n<=h&&x*m<=w;x++){
 43             int cha1=h-n*x,cha2=w-m*x;
 44             if(cha1/(n+1)*(n+1)!=cha1)continue;
 45             else if(cha2/(m+1)*(m+1)!=cha2)continue;
 46             else {
 47                 int dis1=(h-n*x)/(n+1),dis2=(w-m*x)/(m+1);
 48                 if(dis1!=dis2)continue;
 49                 if(dis1>x)continue;
 50                 if(!dis1)continue;
 51                 ans=0,flag=1;
 52                 for(register int i=dis1+1;i<=h;i+=dis1+x){
 53                     for(register int j=dis2+1;j<=w;j+=dis2+x){
 54                         int f=0;
 55                         for(register int ii=i;ii<=i+x-1;ii++){
 56                             if(f)break;
 57                             for(register int jj=j;jj<=j+x-1;jj++){
 58                                 if(map[ii][jj]){
 59                                     f=1;
 60                                     break;
 61                                 }
 62                             }
 63                         }
 64                         if(f)ans+=t;
 65                     }
 66                 }
 67                 for(register int i=0;i<=n;i++){
 68                     for(register int j=0;j<=m;j++){
 69                         int si=i*(x+dis1)+1;
 70                         int sj=j*(x+dis1)+1;
 71                         for(register int ii=si;ii<=si+dis1-1;ii++){
 72                             if(col[i][j])break;
 73                             for(register int jj=sj;jj<=sj+dis2-1;jj++){
 74                                 if(!map[ii][jj]){
 75                                     col[i][j]=1;
 76                                     break;
 77                                 }
 78                             }
 79                         }
 80                     }
 81                 }
 82                 for(register int i=0;i<=n;i++){
 83                     for(register int j=0;j<m;j++){
 84                         int si=i*(x+dis1)+1;
 85                         int sj=j*(x+dis1)+dis1+1;
 86                         int f=0;
 87                         for(register int ii=si;ii<=si+dis1-1;ii++){
 88                             if(f)break;
 89                             for(register int jj=sj;jj<=sj+x-1;jj++){
 90                                 if(!map[ii][jj]){
 91                                     f=1;
 92                                     ans+=t;
 93                                     for(register int k=0;k<=m;k++){
 94                                         col[i][k]=0;
 95                                     }
 96                                     break;
 97                                 }
 98                             }
 99                         }
100                         if(f)break;
101                     }
102                 }
103                 for(register int j=0;j<=m;j++){
104                     for(register int i=0;i<n;i++){
105                         int si=i*(x+dis1)+dis1+1;
106                         int sj=j*(x+dis1)+1;
107                         int f=0;
108                         for(register int ii=si;ii<=si+x-1;ii++){
109                             if(f)break;
110                             for(register int jj=sj;jj<=sj+dis1-1;jj++){
111                                 if(!map[ii][jj]){
112                                     f=1;
113                                     ans+=t;
114                                     for(register int k=0;k<=n;k++){
115                                         col[k][j]=0;
116                                     }
117                                     break;
118                                 }
119                             }
120                         }
121                         if(f)break;
122                     }
123                 }
124                 for(register int i=0;i<=n;i++){
125                     for(register int j=0;j<=m;j++){
126                         if(col[i][j]){
127                             add(i+1,j+1);
128                         }
129                     }
130                 }
131                 for(register int i=1;i<=n+1;i++){
132                     memset(vis,0,sizeof(vis));
133                     if(dfs(i)){
134                         ans+=t;
135                     }
136                 }
137                 final=min(final,ans);
138             }
139         }
140         if(!flag){
141             cout<<-1<<endl;
142             continue;
143         }
144         cout<<final<<endl;
145     }
146 }

猜你喜欢

转载自www.cnblogs.com/Fang-Hao/p/9495102.html
ZOJ