题意: 给定N个点(环状),每次可以销毁连续的三个点, 每个点有一个权值。
问达到全部销毁的状态权值和最小为多少。(每一个状态下,存活的点的权值都要加)
3 ≤ N ≤ 20
think: 显然可以状压。但是貌似也有大佬直接搜出来的。。。人与人之间的差距呀~这个我觉得可能不太好想。。。
首先我们要搜出来的答案是 dp[(1<<(n) - 1]
dp[state]可以由 dp[next_state] + 下一个状态下的伤害值得到。
仔细思考下两个边界 最初和最后。 显然dp[0] = 0;
拿最开始的状态说, 我要销毁掉三个 那么是不要这三个的权值的,
所以dp[(1<<(n) - 1] = dp[下一个状态] + 下一个状态下的权值和。
ps: 老师说有个学姐为了刷DP直接就刷了两百多道。
#include <bits/stdc++.h>
#define ll long long
#define ms(x) memset(x, 0, sizeof(x))
#define inf 0x3f3f3f3f
#define mf(x) memset(x, inf, sizeof(x))
using namespace std;
const int N = 2003;
int a[N], n;
int dp[(1<<20)+5];
int ans;
int dfs(int sta){
if(dp[sta]!=inf){
return dp[sta];
}
for(int i=1;i<=n;i++){
int tmp = sta;
if(sta & (1<<(i-1)) ){
int l, r, damage = 0;
if(i == 1){
l = n;
} else l = i-1;
if(i == n){
r = 1;
} else r = i+1;
tmp -= 1<<(i-1);
if(tmp & (1<<(l-1))){
tmp -= (1<<(l-1));
}
if(tmp & (1<<(r-1)) ){
tmp -= (1<<(r-1));
}
for(int j=1; j<=n; j++){
if(tmp & 1<<(j-1)){
damage += a[j];
}
}
dp[sta] = min(dp[sta], dfs(tmp) + damage);
}
}
return dp[sta];
}
int main()
{
scanf("%d", &n);
for(int i=1;i<=n;i++){
scanf("%d", &a[i]);
}
mf(dp);
dp[0] = 0;
cout<<dfs((1<<n) - 1)<<endl;
return 0;
}
本文探讨了一个环状点销毁问题,通过状态压缩动态规划(状压DP)的方法来寻找使得所有点被销毁时权值和最小的方案。文章提供了完整的代码实现,并解释了如何递归地构建解决方案。
&spm=1001.2101.3001.5002&articleId=80527043&d=1&t=3&u=580f31ac3a5d40c599e8613e1a2387f4)
966

被折叠的 条评论
为什么被折叠?



