URAL - 1152 状压DFS(本质上还是DP)

题意: 给定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;
}


扫描二维码关注公众号,回复: 1684023 查看本文章

         



猜你喜欢

转载自blog.csdn.net/khn64/article/details/80527043