zoukankan      html  css  js  c++  java
  • 状压DP问题

    状态压缩·一

    题目传送:#1044 : 状态压缩·一

    AC代码:

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <deque>
    #include <queue>
    #include <stack>
    #include <bitset>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <complex>
    #include <cstdlib>
    #include <cstring>
    #include <fstream>
    #include <sstream>
    #include <utility>
    #include <iostream>
    #include <algorithm>
    #include <functional>
    #define LL long long
    #define INF 0x7fffffff
    using namespace std;
    
    int n, m, q;
    int w[1005];
    
    int dp[1005][1030];//dp[i][j]表示选到第i个位置时j状态能够取得的最大值
    int cnt[1030];//代表每一个数的位数上的1的个数
    
    int main() {
        cnt[0] = 0, cnt[1] = 1;
        for(int i = 2; i < 1030; i ++) cnt[i] = cnt[i >> 1] + cnt[i & 1];
    
        scanf("%d %d %d", &n, &m, &q);
        for(int i = 1; i <= n; i ++) {
            scanf("%d", &w[i]);
        }
    
        int ans = 0;
        int d = 1 << m;
        for(int i = 1; i <= n; i ++) {
            for(int j = 0; j < (1 << m); j ++) {
                if(cnt[j] <= q) dp[i][j] = max(dp[i-1][j >> 1], dp[i-1][(j >> 1) + (1 << (m - 1))]) + (j & 1) * w[i];
                ans = max(ans, dp[i][j]);
            }
        }
    
        printf("%d
    ", ans);
        return 0;
    }
    



    Hackers’ Crackdown

    题目传送:UVA - 11825 - Hackers’ Crackdown

    AC代码:

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <deque>
    #include <queue>
    #include <stack>
    #include <bitset>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <complex>
    #include <cstdlib>
    #include <cstring>
    #include <fstream>
    #include <sstream>
    #include <utility>
    #include <iostream>
    #include <algorithm>
    #include <functional>
    #define LL long long
    #define INF 0x7fffffff
    using namespace std;
    
    const int maxn = (1 << 16) + 5;
    int dp[maxn];//dp[i]表示子集i最多能够分成多少组
    int cover[maxn];//cover[i]表示若干集合(i中所表示的集合)的并集
    
    int n, m;
    int P[25];//P[i]表示与i相连的数的集合(包含i)
    
    int main() {
        int cas = 1;
        while(scanf("%d", &n) != EOF) {
            if(n == 0) break;
            for(int i = 0; i < n; i ++) {
                scanf("%d", &m);
                P[i] = 1 << i;
                int t;
                while(m --) {
                    scanf("%d", &t);
                    P[i] |= (1 << t);//并入集合i
                }
            }
            for(int i = 0; i < maxn; i ++) {
                cover[i] = 0;
                for(int j = 0; j < n; j ++) {//if推断j是否在i中,是得话就并入
                    if(i & (1 << j)) cover[i] |= P[j];
                }
            }
            dp[0] = 0;
            int tot = (1 << n) - 1;//全集总数
            for(int i = 1; i <= tot; i ++) {//依次枚举全集,由于要先算出前一状态才干推出后一状态
                dp[i] = 0;
                for(int j = i; j; j = (j - 1) & i) {//枚举子集的技巧,重点!
                    if(cover[j] == tot) {//i的子集j等于全集,则运行状态转移
                        dp[i] = max(dp[i], dp[i ^ j] + 1);
                    }
                }
            }
            printf("Case %d: %d
    ", cas ++, dp[tot]);
        }
        return 0;
    }
    



    Sharing Chocolate

    题目传送:UVALive - 4794 - Sharing Chocolate

    WF2010的题。

    AC代码:

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <deque>
    #include <queue>
    #include <stack>
    #include <bitset>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <complex>
    #include <cstdlib>
    #include <cstring>
    #include <fstream>
    #include <sstream>
    #include <utility>
    #include <iostream>
    #include <algorithm>
    #include <functional>
    #define LL long long
    #define INF 0x7fffffff
    using namespace std;
    
    const int maxn = 16;
    int d[1 << maxn][105];
    int vis[1 << maxn][105];
    int sum[1 << maxn];
    int a[maxn];
    int n;
    
    int bitcount(int x) {
        return x == 0 ? 0 : bitcount(x / 2) + (x & 1);
    }
    
    int dp(int s, int x) {//每次递归找出集合为s。宽为x的巧克力能否够满足要求
        if(vis[s][x]) return d[s][x];
        vis[s][x] = 1;
        int& ans = d[s][x];
        if(bitcount(s) == 1) return ans = 1;//此时为边界。即仅仅有一块巧克力的情况,肯定是满足的
        int y = sum[s] / x;//还有一个边长能够依据这个求得
        for(int s0 = (s - 1) & s; s0; s0 = (s0 - 1) & s) {//枚举子集
            int s1 = s - s0;
            if(sum[s0] % x == 0 && dp(s0, min(x, sum[s0] / x)) && dp(s1, min(x, sum[s1] / x))) return ans = 1;//竖着切(这里假定宽x是竖着的)
            if(sum[s0] % y == 0 && dp(s0, min(y, sum[s0] / y)) && dp(s1, min(y, sum[s1] / y))) return ans = 1;//横着切
        }
        return ans = 0;
    }
    
    int main() {
        int cas = 1, x, y;
        while(scanf("%d", &n) != EOF) {
            if(n == 0) break;
            scanf("%d %d", &x, &y);
            for(int i = 0; i < n; i ++) scanf("%d", &a[i]);
    
            //计算每一个子集的元素的和
            memset(sum, 0, sizeof(sum));
            for(int s = 0; s < (1 << n); s ++) {
                for(int i = 0; i < n; i ++) if(s & (1 << i)) sum[s] += a[i];
            }
    
            memset(vis, 0, sizeof(vis));
            int ALL = (1 << n) - 1;
            int ans;
            if(sum[ALL] != x * y) ans = 0;
            else ans = dp(ALL, min(x, y));
            printf("Case %d: %s
    ", cas ++, ans ?

    "Yes" : "No"); } return 0; }



  • 相关阅读:
    作业三3
    作业三2(改过)
    第一章
    实验2
    第三章
    例2-11
    例2-10
    例2-8
    例2-9
    例2-7
  • 原文地址:https://www.cnblogs.com/claireyuancy/p/7113239.html
Copyright © 2011-2022 走看看