poj 2032

 

Square Carpets
Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 529   Accepted: 155

Description

Mr. Frugal bought a new house. He feels deeply in love with his new house because it has a comfortable living room in which he can put himself completely at ease. He thinks his new house is a really good buy. 
But, to his disappointment, the floor of its living room has some scratches on it. 

The floor has a rectangle shape, covered with square panels. He wants to replace all the scratched panels with flawless panels, but he cannot afford to do so. Then, he decides to cover all the scratched panels with carpets. 

The features of the carpets he can use are as follows. 

> Carpets are square-shaped. 
> Carpets may overlap each other. 
> Carpets cannot be folded. 
> Different sizes of carpets are available. Lengths of sides of carpets are multiples of that of the panels. 

The carpets must cover all the scratched panels, but must not cover any of the flawless ones. 

For example, if the scratched panels are as shown in Figure 1, at least 6 carpets are needed. 
poj 2032_第1张图片 
Figure 1: Example Covering
As carpets cost the same irrespective of their sizes, Mr. Frugal would like to use as few number of carpets as possible. 

Your job is to write a program which tells the minimum number of the carpets to cover all the scratched panels. 

Input

The input consists of multiple data sets. As in the following, the end of the input is indicated by a line containing two zeros. 

DataSet1 
DataSet2 
... 
DataSetn 
0 0 

Each data set (DataSeti) represents the state of a floor. The format of a data set is as follows. 

W H 
P11 P12 P13 ... P1W 
P21 P22 P23 ... P2W 
... 
PH1 PH2 PH3 ... PHW 

The positive integers W and H are the numbers of panels on the living room in the x- and y- direction, respectively. The values of W and H are no more than 10. The integer Pyx represents the state of the panel. The value of Pyx means, 

0: flawless panel (must not be covered), 
1: scratched panel (must be covered). 

Output

For each data set, your program should output a line containing one integer which represents the minimum number of the carpets to cover all of the scratched panels.

Sample Input

4 3
0 1 1 1
1 1 1 1
1 1 1 1
8 5
0 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 0 1 1 1 1
0 1 1 1 0 1 1 1
8 8
0 1 1 0 0 1 1 0
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
0 1 1 0 0 1 1 0
0 1 1 0 0 1 1 0
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
0 1 1 0 0 1 1 0
10 10
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 0 1 1 0 1 1 0 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 0 1 1 0 1 1 0 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 0 1 1 0 1 1 0 1
1 1 1 1 1 1 1 1 1 1
0 0

Sample Output

2
6
14
29

Source

Japan 2003 Domestic

分析:此题实在是看不出什么算法,只好爆搜了,但是算一下时间复杂度必然超时,于是有必要做强大的剪枝。。。

          以下摘自某牛博客:http://hi.baidu.com/billdu/blog/item/e24439a5ca9efae29052ee87.html

          首先注意这样一个事情:地毯越大越好。放大地毯的话,由于可以地毯之间覆盖,是没有任何损失的。所以说先用一个动态规划求出来以每个格子为左上角的正方形地毯最大能有多大(转移方程 f[i][j] = min(f[i + 1][j], f[i][j + 1], f[i + 1][j + 1]) + 1,如果(i, j)不能盖住则f[i][j] = 0)。这样我们就得到了W * H个正方形。之后进一步扫描,如果某个正方形被另外的正方形完全包含就把它删掉,这样能进一步减少可行正方形方案的数量。

然后预处理一张表,看看需要被覆盖的格子用哪些正方形可以盖住。

之后就变成了这样一个问题:

从一些正方形中选取最少数量的正方形,使得所有的要被盖住的格子都被盖住。

这样的问题有一个一般情况下非常精准的估价函数:首先将计数器清零。之后扫描每一个格子,如果没有被盖住,就先将计数器加一,然后将所有能将其覆盖的正方形全覆盖上去。循环往复,最后返回计数器的值。

此函数的相容性显然。用上这个,此题就可以0MS过掉了~~

 

可是我还是没0ms,囧~~~我又水了

贴下代码:

#include <stdio.h> #include <vector> using namespace std; bool map[10][10],p[100]; char f[10][10],g[100][2]; vector<char>d[10][10]; int n,m,ans,t; inline int min(int a,int b) { return a<b?a:b; } inline int fun() { int tot=0,i,j,k; bool q[100]; for(i=0;i<t;++i)q[i]=p[i]; for(i=0;i<n;++i) for(j=0;j<m;++j) if(map[i][j]) { for(k=0;k<d[i][j].size();++k) if(q[d[i][j][k]])break; if(k==d[i][j].size()) { ++tot; for(k=0;k<d[i][j].size();++k)q[d[i][j][k]]=1; } } return tot; } void dfs(int x,int y,int now) { if(now+fun()>=ans)return; if(y==m)y=0,++x; if(x==n) { ans=now; return; } bool cover=0; for(int k=0;k<d[x][y].size();++k) if(p[d[x][y][k]]) { cover=1; break; } if(map[x][y]==0||cover) { dfs(x,y+1,now); return; } for(int k=0;k<d[x][y].size();++k) { p[d[x][y][k]]=1; dfs(x,y+1,now+1); p[d[x][y][k]]=0; } } int main(int argc, char* argv[]) { int i,j,k,l; while(scanf("%d %d",&m,&n),n) { for(i=0; i<n; ++i) for(j=0; j<m; ++j) scanf("%d",&k),map[i][j]=f[i][j]=k; for(i=n-2; i>=0; --i) for(j=m-2; j>=0; --j) if(map[i][j])f[i][j]=min(f[i+1][j],min(f[i][j+1],f[i+1][j+1]))+1; t=0; for(i=0; i<n; ++i) for(j=0; j<m; ++j) { for(k=0; k<=i; ++k) for(l=0; l<=j; ++l) { if(k==i&&l==j)continue; if(i+f[i][j]<=k+f[k][l]&&j+f[i][j]<=l+f[k][l])f[i][j]=0; } if(f[i][j]>0)g[t][0]=i,g[t][1]=j,++t; } for(i=0; i<n; ++i) for(j=0; j<m; ++j) { d[i][j].clear(); if(map[i][j]) for(k=0;k<t;++k) if(g[k][0]<=i&&g[k][1]<=j&&g[k][0]+f[g[k][0]][g[k][1]]>i&&g[k][1]+f[g[k][0]][g[k][1]]>j)d[i][j].push_back(k); } ans=m*n; dfs(0,0,0); printf("%d/n",ans); } return 0; } 

 

你可能感兴趣的:(poj 2032)