我写了一个问题的递归DP解决方案。对于某些测试用例,解决方案是失败的(它只是过度计数或计数不足一次)。如何仅追溯或打印导致我最终答案的状态?
递归函数是这样的。它需要4个输入。如果之前已经评估过某个特定状态,它将从std::map
返回解决方案,否则会对其进行评估。解决方案以递归方式返回每个州的min
值。
这是尝试解决Play the Dragon
的Google CodeJam 2017 1Aint hd,ad,hk,ak,b,d;
int inf=1e9+1;
map< tuple<int,int,int,int>, int > dp;
int count(int hld, int hlk, int atd, int atk){
if(dp[make_tuple(hld,hlk,atd,atk)]){
return dp[make_tuple(hld,hlk,atd,atk)];
}
else{
if(hlk<=0){
return 0;
}
if(hld<=0){
return inf;
}
if(hlk-atd<=0){
return 1;
}
if(hld==hd-atk){
if(b==0||d==0){
if(b==0&&d!=0){
return dp[make_tuple(hld,hlk,atd,atk)] = 1 + min(
count(hld-atk,hlk-atd,atd,atk),
count(hld-atk+d,hlk,atd,(atk-d)<0?0:(atk-d))
);
}
if(b!=0&&d==0){
return dp[make_tuple(hld,hlk,atd,atk)] = 1 + min(
count(hld-atk,hlk-atd,atd,atk),
count(hld-atk,hlk,atd+b,atk)
);
}
return dp[make_tuple(hld,hlk,atd,atk)] = 1 + count(hld-atk,hlk-atd,atd,atk);
}
return dp[make_tuple(hld,hlk,atd,atk)] = 1 + min(
count(hld-atk,hlk-atd,atd,atk),
min(
count(hld-atk,hlk,atd+b,atk),
count(hld-atk+d,hlk,atd,(atk-d)<0?0:(atk-d))
)
);
}
if(b==0||d==0){
if(b==0&&d!=0){
if(atk<=0){
return dp[make_tuple(hld,hlk,atd,atk)] = 1 + count(hld-atk,hlk-atd,atd,atk);
}
return dp[make_tuple(hld,hlk,atd,atk)] = 1 + min(
count(hld-atk,hlk-atd,atd,atk),
min(
count(hd-atk,hlk,atd,atk),
count(hld-atk+d,hlk,atd,(atk-d)<0?0:(atk-d))
)
);
}
if(b!=0&&d==0){
return dp[make_tuple(hld,hlk,atd,atk)] = 1 + min(
count(hld-atk,hlk-atd,atd,atk),
min(
count(hld-atk,hlk,atd+b,atk),
count(hd-atk,hlk,atd,atk)
)
);
}
if(atk<=0){
return dp[make_tuple(hld,hlk,atd,atk)] = 1 + count(hld-atk,hlk-atd,atd,atk);
}
return dp[make_tuple(hld,hlk,atd,atk)] = 1 + min(
count(hld-atk,hlk-atd,atd,atk),
count(hd-atk,hlk,atd,atk)
);
}
if(atk<=0){
return dp[make_tuple(hld,hlk,atd,atk)] = 1 + min(
count(hld-atk,hlk-atd,atd,atk),
count(hld-atk,hlk,atd+b,atk)
);
}
return dp[make_tuple(hld,hlk,atd,atk)] = 1 + min(
count(hld-atk,hlk-atd,atd,atk),
min(
count(hld-atk,hlk,atd+b,atk),
min(
count(hd-atk,hlk,atd,atk),
count(hld-(atk-d)<0?0:(atk-d),hlk,atd,(atk-d)<0?0:(atk-d))
)
)
);
}
}
答案 0 :(得分:0)
一种简单的方法是将父元组与计算值保持在一起,即如果T是你的元组,则使用std::map <T, std::pair<int, T>>
。
答案 1 :(得分:0)
我认为你的愿望可以有一个解决方案,但它并不简单,实现它你可以在你的代码中引入比现在更多的问题或错误(我建议他们的存在,因为你没有实现正确回答)。我们的想法是使用唯一的id标记任何新的函数调用,并将数据存储在全局某处。调用该函数时,它应具有有关其父ID的信息,并创建自己的id以传递给它将调用的所有分支。完成后,将其id写入父ID数据单元格并显示结果。您在函数中只有一个位置用于分支 - 当您计算两个计数的最小值时。所以你需要在父id数据单元中输入带有id的调用结果,以便在将来的analasys中进行比较。因此,您创建了一个调用结构,它本身就没有信息。主要的是向父id添加一些额外的信息 - 选择哪个分支(我meand,你有15个返回语句和2个选择变体 - 我想你想知道选择了什么)。对于任何选择的分支你和id字段选择标志。通过这个标志,当你的计算结束时,你将从id到id throght你的数据并在屏幕上只写“选择”的数据。祝你好运!