UVALive 4794 Sharing Chocolate
You find that the only thing better than eating chocolate is to share it with friends. Unfortunately your friends are very picky and have different appetites: some would like more and others less of the chocolate that you offer them. You have found it increasingly difficult to determine whether their demands can be met. It is time to writte a program that solves the problem once and for all!
Your chocolate comes as a rectangular bar. The bar consists of same-sized rectangular pieces. To share the chocolate you may break one bar into two pieces along a division between rows or columns of the bar. You or the may then repeatedly break the resulting pieces in the same manner. Each of your friends insists on a getting a single rectangular portion of the chocolate that has a specified number of pieces. You are a little bit insistent as well: you will break up your bar only if all of it can be distributed to your friends, with none left over.
For exampla, Figure 9 shows one way that a chocolate bar consisting of 3 x 4 pieces can be split into 4 parts that contain 6, 3, 2, and 1 pieces respectively, by breanking it 3 times (This corresponds to the first sample input.)

Input
n
15), the number of parts in which the bar is supposed to be split. This is followed by a line containing two integers x and y(1
x, y
100), the dimensions of the chocolate bar. The next line contains n positive integers, giving the number of pieces that are supposed to be in each of the n parts.
The input is terminated by a line containing the integer zero.
Output
For each test case, first display its case number. Then display whether it is possible to break the chocolate in the desired way: display ``Yes" if it is possible, and ``No" otherwise. Follow the format of the sample output.
Sample Input
4
3 4
6 3 2 1
2
2 3
1 5
0
Sample Output
Case 1: Yes
Case 2: No
因为 n 只有15嘛 。。 那么很容易想到一个状态就是 dp[a][b][st] .. 表示 a * b 这么大的一个矩阵
能否组成集合 st 里面的元素..这样.. bool型的 dp[a][b][st] = 1 表示可以 0 表示不可以。
状态就有 x*y* 2^n 个 ,, 转移要用 O(x + y ) .... 花费过大..
那么先处理一个sum[st] 表示 。这个st这个集合的巧克力的面积和。
那么转移的时候两个子集合的面积和已是确定的...
那么在切一刀的情况下:
sum[st0] %x == 0 才能竖切..
sum[st0] %y == 0 才能横切..
既然 sum[st0]满足上述条件 ....sum[st^st0]也必然满足...因为已有sum[st] %x == 0 && sum[st] % y == 0.
那么就可先降一维..用dp[a][st]表示 ....集合st是否可由宽为a的矩阵构成 .. 要转移的状态数也变为O(1)lor~
那里递归bitcount 也要学学~
初始条件就是 x * y == sum[(1<<n)- 1]...
然后进行一个记忆话搜索...
超时:
#include <bits/stdc++.h>
using namespace std;
const int N = ;
const int M = (<<);
bool dp[N][N][M] , vis[N][N][M];
int sum[M] , n , x , y ,area[N]; bool DP( int x , int y , int st )
{
if( x > y )swap( x , y );
if( vis[x][y][st] ) return dp[x][y][st];
vis[x][y][st] = true;
for( int st0 = st ; st0 ; st0 = (st0-)&st ){
for( int i = ; i <= ( x - )/ ; ++i ) {
if( sum[st0] == i * y && sum[st^st0] == (x-i) * y && DP(i,y,st0) && DP(x-i,y,st^st0) ) return dp[x][y][st] = true;
if( sum[st^st0] == i * y && sum[st0] == (x-i) * y && DP(i,y,st^st0) && DP(x-i,y,st0) ) return dp[x][y][st] = true;
}
for( int j = ; j <= ( y - ) / ; ++j ){
if( sum[st0] == x * j && sum[st^st0] == x*(y-j) && DP(x,j,st0) && DP(x,y-j,st^st0)) return dp[x][y][st] = true;
if( sum[st^st0] == x * j && sum[st0] == x*(y-j)&& DP(x,j,st^st0) && DP(x,y-j,st0)) return dp[x][y][st] = true;
}
}
return dp[x][y][st] = false;
} void init()
{
memset( dp , false , sizeof dp );
memset( vis , false , sizeof vis );
memset( sum , ,sizeof sum );
} void run()
{
cin >> x >> y ;
init();
for( int i = ; i < n ; ++i ) {
cin >> area[i] ;
if( area[i] > x * y ) { cout << "No" << endl; return ;}
for( int a = ; a * a <= area[i] ; ++a ){
if( area[i] % a == ){ int b = area[i] / a; dp[a][b][(<<i)] = vis[a][b][(<<i)] = true ; }
}
}
for( int st = ; st < (<<n); ++st ){
for( int i = ; i < ; ++i ){
if( st & (<<i) ) sum[st] += area[i] ;
}
}
int ALL = ( << n ) - ;
if( sum[ALL] != x * y || !DP( x , y , ALL ) )cout << "No" << endl;
else cout << "Yes" <<endl ; }
int main()
{
#ifdef LOCAL
freopen("in.txt","r",stdin);
#endif
int cas = ;
while( cin >> n && n ) { cout << "Case "<< cas++ <<": "; run(); }
}
正解:
#include <bits/stdc++.h>
using namespace std;
const int N = ;
const int M = (<<);
bool dp[N][M] , vis[N][M];
int sum[M] , n , x , y ,area[N];
int bitcnt( int st ){ return st == ? : bitcnt(st/) + (st&); }
bool DP( int x , int st )
{
if( vis[x][st] ) return dp[x][st];
vis[x][st] = true;
int y = sum[st] / x ;
if( bitcnt(st) == ) return dp[x][st] = true;
for( int st0 = st ; st0 ; st0 = (st0-)&st ){
if( sum[st0] % x == && DP( min( x , sum[st0]/x ),st0) && DP(min(x,sum[st^st0]/x),st^st0)) return dp[x][st] = true;
if( sum[st0] % y == && DP( min( y , sum[st0]/y ),st0) && DP(min(y,sum[st^st0]/y),st^st0)) return dp[x][st] = true;
}
return dp[x][st] = false;
} void init()
{
memset( dp , false , sizeof dp );
memset( vis , false , sizeof vis );
memset( sum , ,sizeof sum );
} void run()
{
cin >> x >> y ;
init();
for( int i = ; i < n ; ++i ) cin >> area[i] ;
for( int st = ; st < (<<n); ++st ){
for( int i = ; i < ; ++i ){
if( st & (<<i) ) sum[st] += area[i] ;
}
}
int ALL = ( << n ) - ;
if( sum[ALL] != x * y || !DP( x , ALL ) )cout << "No" << endl;
else cout << "Yes" <<endl ;
}
int main()
{
#ifdef LOCAL
freopen("in.txt","r",stdin);
#endif
int cas = ;
while( cin >> n && n ) { cout << "Case "<< cas++ <<": "; run(); }
}
UVALive 4794 Sharing Chocolate的更多相关文章
- 【暑假】[深入动态规划]UVAlive 4794 Sharing Chocolate
UVAlive 4794 Sharing Chocolate 题目: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=12055 ...
- UVALive 4794 Sharing Chocolate(状压,枚举子集)
n的规模可以状压,f[x][y][S]表示x行,y列,S集合的巧克力能否被切割. 预处理出每个状态S对应的面积和sum(S),对于一个合法的状态一定满足x*y=sum(S),实际上只有两个变量是独立的 ...
- UVALive 4794 Sharing Chocolate DP
这道题目的DP思想挺先进的,用状态DP来表示各个子巧克力块.原本是要 dp(S,x,y),S代表状态,x,y为边长,由于y可以用面积/x表示出来,就压缩到了只有两个变量,在转移过程也是很巧妙,枚举S的 ...
- LA 4794 Sharing Chocolate
大白书中的题感觉一般都比较难,能理解书上代码就已经很不错了 按照经验,一般数据较小的题目,都有可能是用状态压缩来解决的 题意:问一个面积为x×y的巧克力,能否切若干刀,将其切成n块面积为A1,A2,, ...
- LA 4794 - Sharing Chocolate dp
题意 有一块\(x*y\)的巧克力,问能否恰好分成n块,每块个数如下 输入格式 n x y a1 a2 a3 ... an 首先\(x \times y 必然要等于 \sum\limits_{i=1} ...
- UVa Live 4794 - Sharing Chocolate 枚举子集substa = (s - 1) & substa,记忆化搜索 难度: 2
题目 https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_pr ...
- UVa 1009 Sharing Chocolate (数位dp)
题目链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_proble ...
- LA4794 Sharing Chocolate
传送门 记忆化搜索. 在下觉得sxy大佬的代码写得相当好,通篇的骚操作(因为我都不会呀),%%% 学到了 预处理每个状态的值.以前的我都是zz地枚举每一位.. for(int i=1;i<(1& ...
- 状压DP问题
状态压缩·一 题目传送:#1044 : 状态压缩·一 AC代码: #include <map> #include <set> #include <list> #in ...
随机推荐
- 分布式系统架构常识:CAP理论。
什么是CAP理论? 2000年7月,加州大学伯克利分校的Eric Brewer教授在ACM PODC会议上提出CAP猜想.2年后麻省理工学院的Seth Gilbert和NancyLynch从理论上证明 ...
- thinkphp中的exp查询
今天遇到一个问题,就是在vendor表中查询出vendor_id = vendor_f_id的数据,其实使用原生的sql语句是非常简单的: select * from vendor where ven ...
- python基础----找零问题
给定要找回的总钱数和硬币的种类,求出找零所需最少的硬币数目. 例如: 总钱数63,硬币种类为25.21.10.5.1,求出最小硬币数 分析: 我们可以先假设只有一种硬币1, 假如总钱数为1,硬币数就为 ...
- Fix invisible cursor issue in Ubuntu 13.10
Fix invisible cursor issue in Ubuntu 13.10 Fixing this problem is rather too easy. Open a terminal ( ...
- CSS中表示颜色的4种方法
#1:直接用颜色名称 #2:十六进制数 #3:RGB整数设置颜色 0-255 #4:RGB百分数设置颜色0%-100%
- showmount - 显示关于 NFS 服务器文件系统挂载的信息
总览 /usr/sbin/showmount [ -adehv ] [ --all ] [ --directories ] [ --exports ] [ --help ] [ --version ] ...
- 2019HDU多校第一场 BLANK DP
题意:有四种数字,现在有若干个限制条件:每个区间中不同的数字种类必须是多少种,问合法的方案数. 思路: 定义 dp[i][j][k][t] 代表填完前 t 个位置后,{0,1,2,3} 这 4 个数字 ...
- 你(可能)不知道的 web api
转自奇舞周刊 简介 作为前端er,我们的工作与web是分不开的,随着HTML5的日益壮大,浏览器自带的webapi也随着增多.本篇文章主要选取了几个有趣且有用的webapi进行介绍,分别介绍其用法.用 ...
- 数据库索引原理,及MySQL索引类型(转)
在数据库表中,对字段建立索引可以大大提高查询速度.假如我们创建了一个 mytable表: CREATE TABLE mytable( ID INT NOT NULL, username ) NOT N ...
- disk或者Partition镜像的制作
备份镜像还原一般都是在client-server端这边才有涉及,不过作为平时爱折腾的咸鱼,表示偶尔玩玩这种操作也不错: 工具:pc X 1(装有 大白菜,装机吧,一类制作pe软件的即可,大同小异) ...