利用DeepSeek动态规划求解advent of code 2024年19题

原题地址 https://adventofcode.com/2024/day/19
以下是DeepSeek译文

第 19 天:亚麻布陈列

今天,历史学家们带你去了齿轮岛上的温泉!非常可疑的是,当他们开始仔细搜索广阔的螺旋田野时,绝对没有任何问题发生。

这终于可能是你参观隔壁温泉的机会了吗?只有一种方法能知道。

在与温泉前台的接待人员简短交谈后,你发现自己没有正确种类的钱来支付入场费。然而,在你离开之前,工作人员引起了你的注意。显然,他们听说了你如何在温泉帮忙,并且愿意做个交易:如果你能简单地帮他们整理毛巾,他们就让你免费入场!

这个温泉的每条毛巾都标有一种彩色条纹图案。只有少数几种图案,但对于任何特定图案,工作人员都可以为你提供所需数量的带有该图案的毛巾。每条条纹可以是白色 (w)、蓝色 (u)、黑色 (b)、红色 ® 或绿色 (g)。因此,带有图案 ggr 的毛巾会有一条绿色条纹、一条绿色条纹,然后是一条红色条纹,按此顺序。(你不能通过将毛巾上下翻转来反转图案,因为那会导致温泉标志朝向错误。)

官方温泉品牌专家制作了一个设计列表——每个设计都是一长串条纹颜色——他们希望能够展示这些设计。你可以使用任何你想要的毛巾,但所有毛巾的条纹必须完全符合所需的设计。因此,要展示设计 rgrgr,你可以使用两条 rg 毛巾和一条 r 毛巾,或者一条 rgr 毛巾和一条 gr 毛巾,甚至一条巨大的 rgrgr 毛巾(假设这种毛巾图案确实可用)。

首先,收集所有可用的毛巾图案和所需的设计列表(你的谜题输入)。例如:

r, wr, b, g, bwu, rb, gb, br

brwrr
bggr
gbbr
rrbgbr
ubwu
bwurrg
brgr
bbrgwb

第一行表示可用的毛巾图案;在这个例子中,温泉拥有无限数量的带有一条红色条纹 ® 的毛巾,无限数量的带有一条白色条纹和一条红色条纹 (wr) 的毛巾,等等。

在空行之后,其余各行描述了一个温泉希望展示的设计。在这个例子中,第一个设计 (brwrr) 表示温泉希望展示一条黑色条纹、一条红色条纹、一条白色条纹,然后是两条红色条纹,按此顺序。

并非所有设计都能用可用的毛巾实现。在上面的例子中,设计的可实现与否如下:

  • brwrr 可以用一条 br 毛巾,然后一条 wr 毛巾,最后一条 r 毛巾制成。
  • bggr 可以用一条 b 毛巾,两条 g 毛巾,然后一条 r 毛巾制成。
  • gbbr 可以用一条 gb 毛巾和一条 br 毛巾制成。
  • rrbgbr 可以用 r, rb, g, 和 br 制成。
  • ubwu 无法实现。
  • bwurrg 可以用 bwu, r, r, 和 g 制成。
  • brgr 可以用 br, g, 和 r 制成。
  • bbrgwb 无法实现。

在这个例子中,八个设计中有 6 个是可以用可用的毛巾图案实现的。

为了尽快进入温泉,请仔细查阅你的毛巾图案和所需设计列表。有多少个设计是可能实现的?

要开始,请获取你的谜题输入。

第二部分

工作人员并不完全喜欢你提出的一些毛巾摆放方案。为了避免无休止的毛巾重新摆放循环,也许你应该直接给他们所有可能的选择。

以下是上述示例中各个设计所有不同的实现方式:

  • brwrr 可以通过两种不同的方式实现:b, r, wr, rbr, wr, r

  • bggr 只能通过 b, g, g, r 这一种方式实现。

  • gbbr 可以通过 4 种不同的方式实现:

    • g, b, b, r
    • g, b, br
    • gb, b, r
    • gb, br
  • rrbgbr 可以通过 6 种不同的方式实现:

    • r, r, b, g, b, r
    • r, r, b, g, br
    • r, r, b, gb, r
    • r, rb, g, b, r
    • r, rb, g, br
    • r, rb, gb, r
  • bwurrg 只能通过 bwu, r, r, g 这一种方式实现。

  • brgr 可以通过两种不同的方式实现:b, r, g, rbr, g, r

  • ubwubbrgwb 仍然无法实现。

将此示例中所有毛巾可以排列成所需设计的方式数量相加,得到 16 (2 + 1 + 4 + 6 + 1 + 2)。

只要你有了这个列表,他们就会让你进入温泉。如果将你能实现每个设计的不同方式的数量相加,你会得到什么?

我用SQL做出来了第一部分题目中的例子,但是同样的语句做不出附件全部的解, 因为using key(w)每次会覆盖相同的w,从而把同一个毛巾的不同组合漏掉, 使结果偏小

with recursive co as(
select trim(unnest(string_split(c, ',')))c from (from read_csv('2419-input0.txt', header=0, delim='-')t(c) limit 1)), 
w as(select * from read_csv('2419-input0.txt', header=0, delim='-', skip=2) t(w)),
t using key(w)as(select 1 lv , w,w s from w
union 
select lv+1,w, substr(s, length(c)+1) from t,co where s like c||'%' and s<>''
and lv<80)
select count(*)from t where s='';

实在想不出来就丢给DeepSeek,

编写python函数,判断字符串a能否由一个字符串集合b中的元素组成,集合中的元素允许重复使用,拼接的字符串必须和要判断的字符串相同。比如集合{bi,l,k,ike}能组成bill,不能组成bike
再编写python函数,输出字符串a能由一个字符串集合b中的元素组成的方法数目,集合中的元素允许重复使用,拼接的字符串必须和要判断的字符串相同。比如集合{r, b, g, rb, gb, br},字符串brgr有2种组成方法: b, r, g, r 或 br, g, r,返回2,不能组成的返回0

他把两部分都轻松做对了

def can_compose_string(a: str, b: set) -> bool:
    """
    判断字符串a能否由字符串集合b中的元素组成
    
    Args:
        a: 目标字符串
        b: 字符串集合
        
    Returns:
        bool: 如果能够组成返回True,否则返回False
    """
    n = len(a)
    # dp[i] 表示a的前i个字符能否被b中的字符串组成
    dp = [False] * (n + 1)
    dp[0] = True  # 空字符串可以被组成
    
    for i in range(1, n + 1):
        for j in range(i):
            # 如果前j个字符可以被组成,且a[j:i]在集合b中
            if dp[j] and a[j:i] in b:
                dp[i] = True
                break  # 找到一个可行的分解即可
    
    return dp[n]


def can_compose_string_memo(a: str, b: set) -> bool:
    """
    使用记忆化递归判断字符串a能否由字符串集合b中的元素组成
    """
    memo = {}
    
    def dfs(start):
        if start == len(a):
            return True
        
        if start in memo:
            return memo[start]
        
        for end in range(start + 1, len(a) + 1):
            substring = a[start:end]
            if substring in b and dfs(end):
                memo[start] = True
                return True
        
        memo[start] = False
        return False
    
    return dfs(0)



def find_composition(a: str, b: set):
    """
    返回字符串a的分解方式,如果无法分解返回None
    """
    n = len(a)
    dp = [None] * (n + 1)
    dp[0] = []  # 空字符串的分解为空列表
    
    for i in range(1, n + 1):
        for j in range(i):
            if dp[j] is not None and a[j:i] in b:
                dp[i] = dp[j] + [a[j:i]]
                break
    
    return dp[n]

import sys
import time

def count_composition_ways_optimized(a: str, b: set) -> int:
    """
    优化版本:限制子串最大长度,提高效率
    """
    n = len(a)
    if n == 0:
        return 1
    
    # 计算集合中字符串的最大长度
    max_len = max(len(word) for word in b) if b else 0
    
    dp = [0] * (n + 1)
    dp[0] = 1
    
    for i in range(1, n + 1):
        # 只检查可能的子串长度,避免不必要的检查
        for length in range(1, min(i, max_len) + 1):
            start = i - length
            if a[start:i] in b:
                dp[i] += dp[start]
    
    return dp[n]

def main():
    if len(sys.argv) != 2:
        print("用法: python script.py <文件名>")
        return
    
    filename = sys.argv[1]
    cnt=0
    try:
        with open(filename, 'r', encoding='utf-8') as file:
            while True:
                line = file.readline().strip()
                if line == '':
                    break
                print(f"题目: {line}")
                t = time.time()
                cnt+=count_composition_ways_optimized(line, b)
                #if can_compose_string(line, b):
                #    cnt+=1
                #    print(f"题目有解: {line}")

                #print(f"耗时: {round(time.time()-t, 4)} s")
    except FileNotFoundError:
        print(f"错误: 文件 '{filename}' 不存在")
    except Exception as e:
        print(f"错误: {e}")
    print(cnt)

#列表b保存从附件输入的子串集合, 以下只列出部分。待求解字符串保存在文件中用命令行输入文件名
b=['grbuu','bbg','rwrwrru','bw','gwburwr','gubgu','wrbug','brrb']
if __name__ == "__main__":
    main()

其实第一部分的结果也可以用第二部分的函数顺便得出。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值