UVa Live 4794 - Sharing Chocolate 枚举子集substa = (s - 1) & substa,记忆化搜索 难度: 2

题目

https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2795

题意

x * y的巧克力,问能不能恰好切成n份(只能整数切),每块大小恰好ai

思路

明显,记忆化搜索。

这里参照刘书使用了sum来通过长计算宽

感想:

这种需要枚举子状态的题总是不敢枚举

代码

#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <string>
#include <tuple>
#define LOCAL_DEBUG
using namespace std;
typedef tuple<int, int, int> MyTask;
typedef pair<int, double> MyPair;
const int MAXN = 101;
const int MAXSTA = 1 << 16;
int ok[MAXN][MAXSTA];
long long sum[MAXSTA];
int n;
int a[MAXN];
int maxsta;

int check(int r, int sta) {
    if (ok[r][sta] != -1)return ok[r][sta];
    if (sum[sta] % r) return ok[r][sta] = 0;
    if ((sta & -sta) == sta)return  ok[r][sta] = 1;
    int c = sum[sta] / r;
    assert(r >= c);
    for (int substa = (sta - 1) & sta; substa != 0; substa = (substa - 1) & sta) {
        if (sum[substa] * 2 < sum[sta])continue;
        if (sum[substa] % r == 0) {
            int othersubsta = sta ^ substa;
            int subr = r;
            int subc = sum[substa] / r;
            int othersubr = r;
            int othersubc = c - subc;
            if (check(max(subr, subc), substa) && check(max(othersubr, othersubc), othersubsta)) {
                return ok[r][sta] = 1;
            }
        }
        else if(sum[substa] % c == 0){
            int othersubsta = sta ^ substa;
            int subr = sum[substa] / c;
            int subc = c;
            int othersubr = r - subr;
            int othersubc = c;
            if (check(max(subr, subc), substa) && check(max(othersubr, othersubc), othersubsta)) {
                return ok[r][sta] = 1;
            }
        }
    }
    return ok[r][sta] = 0;
}

int main() {
#ifdef LOCAL_DEBUG
    freopen("C:\\Users\\Iris\\source\\repos\\ACM\\ACM\\input.txt", "r", stdin);
    //freopen("C:\\Users\\Iris\\source\\repos\\ACM\\ACM\\output.txt", "w", stdout);
#endif // LOCAL_DEBUG
    int T;
    //cin >> T;
    for (int ti = 1;cin>>n && n; ti++) {
        memset(ok, -1, sizeof ok);
        int x, y;
        cin >> x >> y;
        for (int i = 0; i < n; i++) {
            cin >> a[i];
        }
        maxsta = 1 << n;
        for (int sta = 0; sta < maxsta; sta++) {
            sum[sta] = 0;
            for (int i = 0; i < n; i++) {
                if (sta & (1 << i))sum[sta] += a[i];
            }
        }
        if (sum[maxsta - 1] == x * y && check(max(x, y), maxsta - 1)) {
            printf("Case %d: Yes\n", ti);
        }
        else {
            printf("Case %d: No\n", ti);
        }
    }

    return 0;
}

原文地址:https://www.cnblogs.com/xuesu/p/10468778.html

时间: 2024-10-12 02:18:30

UVa Live 4794 - Sharing Chocolate 枚举子集substa = (s - 1) & substa,记忆化搜索 难度: 2的相关文章

UVa 11825 - Hackers&#39; Crackdown DP, 枚举子集substa = (substa - 1)&amp;sta 难度: 2

题目 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2925 题意 n个节点,每个节点都有完全相同的n项服务. 每次可以选择一个节点,破坏该节点和相邻节点的某项服务. 问最多能完全破坏多少服务? 思路 如刘书, 直接枚举状态的子集 注意元素个数为k的集合有C^k_n个子集,那么枚举的时间复杂度为sum{c^k_n * 2^k} = 3^n

LA 4794 Sharing Chocolate

大白书中的题感觉一般都比较难,能理解书上代码就已经很不错了 按照经验,一般数据较小的题目,都有可能是用状态压缩来解决的 题意:问一个面积为x×y的巧克力,能否切若干刀,将其切成n块面积为A1,A2,,,An块巧克力.(每次只能沿直线切一块巧克力) 设计状态: f(r, c, S) = 1表示r行c列的巧克力可以切成面积集合为S的若干块巧克力 分解问题: f(r, c, S) = 1当且仅当 横着切:存在1≤r0<r和S的子集S0,使得f(r0, c, S0) = f(r-r0,c, S-S0)

HDU 4085 Peach Blossom Spring 记忆化搜索枚举子集 斯坦纳树

题目链接:点击打开链接 题意: 第一行输入n个点 m条可修建的无向边 k个人 下面给出修建的边和修建该边的花费. 开始时k个人在1-k的每个点上(一个点各一人) 目标:从m条给定边中修建部分边使得花费和最小 让k个人移动到 [n-k+1, n] 后面的k个点上(每个点放一个人). 思路: 首先就是一道斯坦纳树,还是先求一个dp数组(求解方法:点击打开链接) dp[i][j] 表示以i为根 ,j为8个点中是否在 i 的子树里 时的最小花费. 现在的问题就是如何求答案. 因为一个人到他的目标点这条路

uva 10581 - Partitioning for fun and profit(记忆化搜索+数论)

题目链接:uva 10581 - Partitioning for fun and profit 题目大意:给定m,n,k,将m分解成n份,然后按照每份的个数排定字典序,并且划分时要求ai?1≤ai,然后输出字典序排在k位的划分方法. 解题思路:因为有ai?1≤ai的条件,所以先记忆化搜索处理出组合情况dp[i][j][s]表示第i位为j,并且剩余的未划分数为s的总数为dp[i][j][s],然后就是枚举每一位上的值,判断序列的位置即可. #include <cstdio> #include

UVA 10003 Cutting Sticks 区间DP+记忆化搜索

UVA 10003 Cutting Sticks+区间DP 纵有疾风起 题目大意 有一个长为L的木棍,木棍中间有n个切点.每次切割的费用为当前木棍的长度.求切割木棍的最小费用 输入输出 第一行是木棍的长度L,第二行是切割点的个数n,接下来的n行是切割点在木棍上的坐标. 输出切割木棍的最小费用 前话-区间dp简单入门 区间dp的入门下面博客写的非常好,我就是看的他们博客学会的,入门简单,以后的应用就得靠自己了. https://blog.csdn.net/qq_41661809/article/d

uva 1076 - Password Suspects(AC自动机+记忆化搜索)

题目链接:uva 1076 - Password Suspects 题目大意:有一个长度为n的密码,存在m个子串,问说有多少种字符串满足,如果满足个数不大于42,按照字典序输出. 解题思路:根据子串构建AC自动机,然后记忆化搜索,dp[i][u][s]表示第i个字符,在u节点,匹配s个子串. #include <cstdio> #include <cstring> #include <queue> #include <string> #include <

UVa 1252 - Twenty Questions(记忆化搜索,状态压缩dp)

题目链接:uva 1252 题意: 有n个长度为m的二进制串,每个都是不同的. 为了把所有字符串区分开,你可以询问,每次可以问某位上是0还是1. 问最少提问次数,可以把所有字符串区分开来. 思路来源于:点击打开链接 思路: m很小,可以考虑状态压缩. dp[s1][s2]表示询问的状态为s1时,此时能猜到状态包含s2时最小需要的步数. 当询问的几位=s2的二进制串小于2时就能区分出来了,dp[s1][s2]=0: 不能区分则再询问一次,s1|=(1<<k),如果问某位为0,则s2不变,问某位为

UVA - 10118Free Candies(记忆化搜索)

题目:UVA - 10118Free Candies(记忆化搜索) 题目大意:给你四堆糖果,每个糖果都有颜色.每次你都只能拿任意一堆最上面的糖果,放到自己的篮子里.如果有两个糖果颜色相同的话,就可以将这对糖果放进自己的口袋.自己的篮子最多只能装5个糖果,如果满了,游戏就结束了.问你能够得到的最多的糖果对数. 解题思路:这题想了好久,好不容易把状态想对了,结果脑子发热,又偏离了方向.dp[a][b][c][d]:四堆糖果现在在最上面的是哪一个.因为下面的糖果如果确定了,那么接下了不管你怎么取,最优

UVA - 10817 Headmaster&#39;s Headache (状压dp+记忆化搜索)

题意:有M个已聘教师,N个候选老师,S个科目,已知每个老师的雇佣费和可教科目,已聘老师必须雇佣,要求每个科目至少两个老师教的情况下,最少的雇佣费用. 分析: 1.为让雇佣费尽可能少,雇佣的老师应教他所能教的所有科目. 2.已聘老师必须选,候选老师可选可不选. 3.dfs(cur, subject1, subject2)---求出在当前已选cur个老师,有一个老师教的科目状态为 subject1,有两个及以上老师教的科目状态为 subject2的情况下,最少的雇佣费用. dp[cur][subje