洛谷 P5074 Eat the Trees(插头DP)

题目链接
题意

给出n*m的方格,有些格子不能铺线,其它格子必须铺,可以形成多个闭合回路。问有多少种铺法?

思路

点我 这题的弱化版,可以不考虑插头的括号方向,将合并插头操作允许在每个位置出现即可。

注意全0也是存在1种方案。。

代码

不考虑插头的左右

#include <bits/stdc++.h>
using namespace std;

#define ll long long

struct hash_table {
    ll hash_mod = 590027;
    ll state[600000], ans[600000], up;
    ll tot, first[600000], nxt[600000], w[600000];
    void init() {
        memset(first, 0, sizeof(first));
        tot = 0;
        up = 0;
    }
    ll ins(ll sta, ll val) {
        ll key = sta%hash_mod;
        for(ll i = first[key]; i; i = nxt[i]) {
            if(state[w[i]] == sta) return ans[w[i]] += val;
        }
        state[++up] = sta;
        ans[up] = val;
        nxt[++tot] = first[key];
        w[tot] = up;
        first[key] = tot;
        return val;
    }
}dp[2];

/*hash_table*/
// chatou 0 null, 1 right, 2 down
ll n, m, endx, endy, a[15][15], bit[15];
#define prel (1ll<<bit[j-1])
#define prer (1ll<<bit[j])

void solve() {
    ll cur = 0, ans = 0;
    dp[cur].init();
    dp[0].ins(0,1);
    for(ll i = 1; i <= n; ++i) {
        for(ll j = 1; j <= dp[cur].up; ++j) dp[cur].state[j] <<= 1;
        for(ll j = 1; j <= m; ++j) {
            cur ^= 1;
            dp[cur].init();
            for(ll k = 1; k <= dp[cur^1].up; ++k) {
                ll sta = dp[cur^1].state[k];
                ll w = dp[cur^1].ans[k];
                ll d = (sta>>bit[j])&1ll;
                ll r = (sta>>bit[j-1])&1ll;
                if(!a[i][j]) {
                    if(!d && !r) dp[cur].ins(sta,w);
                }
                else if(!d && !r) {
                    if(a[i+1][j] && a[i][j+1]) dp[cur].ins(sta + prel + prer,w);
                }
                else if(!d && r) {
                    if(a[i+1][j]) dp[cur].ins(sta,w);
                    if(a[i][j+1]) dp[cur].ins(sta-prel+prer,w);
                }
                else if(d && !r) {
                    if(a[i+1][j]) dp[cur].ins(sta+prel-prer,w);
                    if(a[i][j+1]) dp[cur].ins(sta,w);
                }
                else {
                    dp[cur].ins(sta-prel-prer,w);
                }
            }
        }
    }
    printf("%lld\n",dp[cur].ins(0,0));
}

int main() {
    ll t;
    for(scanf("%lld",&t); t; --t) {
        scanf("%lld%lld",&n,&m);
        memset(a,0,sizeof(a));
        for(ll i = 1; i <= n; ++i) {
            for(ll j = 1; j <= m; ++j) {
                scanf("%d",&a[i][j]);
                if(a[i][j]) {
                    endx = i;
                    endy = j;
                }
            }
        }
        for(ll i = 1; i <= 13; ++i) bit[i] = i;
        solve();
    }
	return 0;
}

下为考虑插头的左右,直接CV了上题的代码改改。

STL unordered_map

#include <bits/stdc++.h>
using namespace std;

#define ll long long

unordered_map<ll,ll> dp[3];
// chatou 0 null, 1 right, 2 down
ll n, m, endx, endy, a[15][15], bit[15];
#define prel (1ll<<bit[j-1])
#define prer (1ll<<bit[j])

void solve() {
    ll cur = 0, ans = 0;
    dp[cur].clear();
    dp[0][0] = 1;
    for(ll i = 1; i <= n; ++i) {
        dp[2].clear();
        for(auto j : dp[cur]) dp[2][j.first<<2] = j.second;
        dp[cur] = dp[2];
        for(ll j = 1; j <= m; ++j) {
            cur ^= 1;
            dp[cur].clear();
            for(auto k : dp[cur^1]) {
                ll sta = k.first;
                ll w = k.second;
                ll d = (sta>>bit[j])&3ll;
                ll r = (sta>>bit[j-1])&3ll;
//                    printf("%lld %lld - %lld %lld\n",i,j,sta,w);
//                    printf("%lld = %lld\n\n",r,d);
                if(!a[i][j]) {
                    if(!r && !d) dp[cur][sta] += w;
                }
                else if(!r && !d) {
                    if(a[i+1][j] && a[i][j+1]) dp[cur][sta + prel + (2*prer)] += w;
                }
                else if(r && !d) {
                    if(a[i+1][j]) dp[cur][sta] += w;
                    if(a[i][j+1]) dp[cur][sta - (r*prel) + (r*prer)] += w;
                }
                else if(!r && d) {
                    if(a[i+1][j]) dp[cur][sta + (d*prel) - (d*prer)] += w;
                    if(a[i][j+1]) dp[cur][sta] += w;
                }
                else if(r == 1 && d == 1) {
                    ll cnt = 1;
                    for(ll p = j+1; p <= m; ++p) {
                        if(((sta>>bit[p])&3ll) == 1) ++cnt;
                        if(((sta>>bit[p])&3ll) == 2) --cnt;
                        if(!cnt) {
                            dp[cur][(sta - (r*prel) - (d*prer)) - (1<<bit[p])] += w;
                            break;
                        }
                    }
                }
                else if(r == 2 && d == 2) {
                    ll cnt = 1;
                    for(ll p = j-2; p >= 0; --p) {
                        if(((sta>>bit[p])&3ll) == 1) --cnt;
                        if(((sta>>bit[p])&3ll) == 2) ++cnt;
                        if(!cnt) {
                            dp[cur][(sta - (r*prel) - (d*prer)) + (1<<bit[p])] += w;
                            break;
                        }
                    }
                }
                else if(r == 2 && d == 1) {
                    dp[cur][sta - (r*prel) - (d*prer)] += w;
                }
                else if(r == 1 && d == 2) { // ok
                    dp[cur][sta - (r*prel) - (d*prer)] += w;
                    if(i == endx && j == endy) ans += w;
                }
            }
        }
    }
    printf("%lld\n",dp[cur][0]);
}

int main() {
    ll t;
    for(scanf("%lld",&t); t; --t) {
        scanf("%lld%lld",&n,&m);
        memset(a,0,sizeof(a));
        for(ll i = 1; i <= n; ++i) {
            for(ll j = 1; j <= m; ++j) {
                scanf("%lld",&a[i][j]);
                if(a[i][j]) {
                    endx = i;
                    endy = j;
                }
            }
        }
        for(ll i = 1; i <= 13; ++i) bit[i] = i<<1;
        solve();
    }
	return 0;
}

hash_table

#include <bits/stdc++.h>
using namespace std;

#define ll long long

struct hash_table {
    ll hash_mod = 590027;
    ll state[600000], ans[600000], up;
    ll tot, first[600000], nxt[600000], w[600000];
    void init() {
        memset(first, 0, sizeof(first));
        tot = 0;
        up = 0;
    }
    ll ins(ll sta, ll val) {
        ll key = sta%hash_mod;
        for(ll i = first[key]; i; i = nxt[i]) {
            if(state[w[i]] == sta) return ans[w[i]] += val;
        }
        state[++up] = sta;
        ans[up] = val;
        nxt[++tot] = first[key];
        w[tot] = up;
        first[key] = tot;
        return val;
    }
}dp[2];

/*hash_table*/
// chatou 0 null, 1 right, 2 down
ll n, m, endx, endy, a[15][15], bit[15];
#define prel (1ll<<bit[j-1])
#define prer (1ll<<bit[j])

void solve() {
    ll cur = 0, ans = 0;
    dp[cur].init();
    dp[0].ins(0,1);
    for(ll i = 1; i <= n; ++i) {
        for(ll j = 1; j <= dp[cur].up; ++j) dp[cur].state[j] <<= 2;
        for(ll j = 1; j <= m; ++j) {
            cur ^= 1;
            dp[cur].init();
            for(ll k = 1; k <= dp[cur^1].up; ++k) {
                ll sta = dp[cur^1].state[k];
                ll w = dp[cur^1].ans[k];
                ll d = (sta>>bit[j])&3ll;
                ll r = (sta>>bit[j-1])&3ll;
//                    printf("%lld %lld - %lld %lld\n",i,j,sta,w);
//                    printf("%lld = %lld\n\n",r,d);
                if(!a[i][j]) {
                    if(!r && !d) dp[cur].ins(sta,w);
                }
                else if(!r && !d) {
                    if(a[i+1][j] && a[i][j+1]) dp[cur].ins(sta + prel + (2*prer),w);
                }
                else if(r && !d) {
                    if(a[i+1][j]) dp[cur].ins(sta,w);
                    if(a[i][j+1]) dp[cur].ins(sta - (r*prel) + (r*prer),w);
                }
                else if(!r && d) {
                    if(a[i+1][j]) dp[cur].ins(sta + (d*prel) - (d*prer),w);
                    if(a[i][j+1]) dp[cur].ins(sta,w);
                }
                else if(r == 1 && d == 1) {
                    ll cnt = 1;
                    for(ll p = j+1; p <= m; ++p) {
                        if(((sta>>bit[p])&3ll) == 1) ++cnt;
                        if(((sta>>bit[p])&3ll) == 2) --cnt;
                        if(!cnt) {
                            dp[cur].ins((sta - (r*prel) - (d*prer)) - (1<<bit[p]),w);
                            break;
                        }
                    }
                }
                else if(r == 2 && d == 2) {
                    ll cnt = 1;
                    for(ll p = j-2; p >= 0; --p) {
                        if(((sta>>bit[p])&3ll) == 1) --cnt;
                        if(((sta>>bit[p])&3ll) == 2) ++cnt;
                        if(!cnt) {
                            dp[cur].ins((sta - (r*prel) - (d*prer)) + (1<<bit[p]),w);
                            break;
                        }
                    }
                }
                else if(r == 2 && d == 1) {
                    dp[cur].ins(sta - (r*prel) - (d*prer),w);
                }
                else if(r == 1 && d == 2) { // ok
                    dp[cur].ins(sta - (r*prel) - (d*prer),w);
                    if(i == endx && j == endy) ans += w;
                }
            }
        }
    }
    printf("%lld\n",dp[cur].ins(0,0));
}

int main() {
    ll t;
    for(scanf("%lld",&t); t; --t) {
        scanf("%lld%lld",&n,&m);
        memset(a,0,sizeof(a));
        for(ll i = 1; i <= n; ++i) {
            for(ll j = 1; j <= m; ++j) {
                scanf("%d",&a[i][j]);
                if(a[i][j]) {
                    endx = i;
                    endy = j;
                }
            }
        }
        for(ll i = 1; i <= 13; ++i) bit[i] = i<<1;
        solve();
    }
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值