轮廓线动态规划问题

好久木有更新了,感觉都有点陌生了,上个月因为各种奇怪的事情都没有好好刷过题,做过的题也没好好总结,so,这个月再好好努力!


Tiling Dominoes

题目传送:UVA - 11270 - Tiling Dominoes

基础的轮廓线动态规划。

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, cur;
LL dp[2][1 << 11];//滚动数组,第二维开到11就好了,不然TLE。

void update(int a, int b) {//状态转移
    if(b & (1 << m)) dp[cur][b ^ (1 << m)] += dp[1 - cur][a];
}

int main() {
    while(scanf("%d%d", &n, &m) != EOF) {
        if(n < m) swap(n, m);
        memset(dp, 0, sizeof(dp));
        cur = 0;
        dp[0][(1 << m) - 1] = 1;//初始状态,表示啥都不放的时候有一种方案
        for(int i = 0; i < n; i ++) {
            for(int j = 0; j < m; j ++) {
                cur ^= 1;
                memset(dp[cur], 0, sizeof(dp[cur]));
                for(int k = 0; k < (1 << m); k ++) {
                    update(k, k << 1);//当前位置不放骨牌
                    if(i && !(k & (1 << m - 1))) update(k, (k << 1) ^ (1 << m) ^ 1);//当前位置竖着放置骨牌
                    if(j && !(k & 1)) update(k, (k << 1) ^ 3);//当前位置横着放置骨牌
                }
            }
        }
        printf("%lld\n", dp[cur][(1 << m) - 1]);
    }
    return 0;
}


Campus Design

题目传送:HDU - 4804 - Campus Design

13年南京赛区银牌题。

轮廓线动态规划或者插头DP。

其实就是上一题的变形。

只不过编码的时候要注意很多细节,对思维能力和编程能力都有提高。

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;

#define MOD 1000000007

int N, M, C, D;
int cur;

char mp[105][25];
int dp[2][1 << 11][22];//注意这里应该开到22,不然会WA。

void update(int a, int b, int c, int d) {
    if(b & (1 << M)) {//为了保证在当前状态下,之前的格子都已经覆盖
        dp[cur][b ^ (1 << M)][c] = (dp[cur][b ^ (1 << M)][c] + dp[1 - cur][a][d]) % MOD;
    }
}

int main() {
    while(scanf("%d %d %d %d", &N, &M, &C, &D) != EOF) {
        for(int i = 0; i < N; i ++) {
            scanf("%s", mp[i]);
        }
        memset(dp, 0, sizeof(dp));
        int tot = (1 << M) - 1;
        cur = 0;
        dp[0][tot][0] = 1;
        for(int i = 0; i < N; i ++) {//枚举每一层
            for(int j = 0; j < M; j ++) {//枚举每一层上的每一列上的阶段
                cur ^= 1;
                memset(dp[cur], 0, sizeof(dp[cur]));
                if(mp[i][j] == '0') {
                    for(int s = 0; s <= tot; s ++) {//枚举上一个阶段的所有状态
                        for(int k = 0; k <= D; k ++) {//上一个状态放了几个1*1的砖块
                            update(s, (s << 1) ^ 1, k, k);//此时不能放砖块,可以理解为已经放好了砖块
                        }
                    }
                }
                else {
                    for(int s = 0; s <= tot; s ++) {//枚举上一个阶段的所有状态
                        for(int k = 0; k <= D; k ++) {//上一个状态放了几个1*1的砖块
                            update(s, (s << 1) ^ 1, k + 1, k);//放一个1*1的砖块,然后转移。
                            update(s, s << 1, k, k);//不放砖块,然后转移。
                            if(i && !(s & (1 << M - 1))) update(s, (s << 1) ^ (1 << M) ^ 1, k, k);//竖着放砖块,然后转移。
                            if(j && !(s & 1)) update(s, (s << 1) ^ 3, k, k);//横着放砖块,然后转移。
                        }
                    }
                }
            }
        }
        int ans = 0;
        for(int i = C; i <= D; i ++) {
            ans = (ans + dp[cur][tot][i]) % MOD;
        }
        printf("%d\n", ans);
    }
    return 0;
}


你可能感兴趣的:(动态规划,uva)