洛谷 P5056 【模板】插头dp

题目链接 题意 给出n*m的方格,有些格子不能铺线,其它格子必须铺,形成一个闭合回路。问有多少种铺法?
思路 比赛时基本做不出来,就学个新算法玩玩。
学习链接
代码对于我这个不会hash_table 的不太友好,先自己封装了一个用着舒服的hash_table,当然也可以直接用STL里的 unordered_map,初学算法我认为直接使用后者更好,循序渐进。
插头dp简单的说还是轮廓线的状压dp?,多考虑了一种连通性问题。
用括号表示法表示轮廓线后,然后考虑状态转移。
枚举每点,考虑左边的朝右插头 r,上边朝下插头 d,左插头1表示,右插头2表示

  • if 当前点是障碍
  • else if (!r && !d)
  • else if (r && !d)
  • else if (!r && d)
  • else if (r == 1 && d == 1)
  • else if (r == 2 && d == 2)
  • else if (r == 1 && d == 2)
  • else if (r == 2 && d == 1)
所有的情况就这么多,然后每点考虑插头形状转移即可
一个坑点 | ^ 运算符优先级不同,不是从左到右运算,然后找了半天bug,还是用 + - 比较稳。
代码 STL unordered_map
代码
991ms
吸氧后 228ms
#include using namespace std; #define ll long longunordered_map dp[3]; // chatou 0 null, 1 right, 2 down ll n, m, endx, endy, a[15][15], bit[15]; #define prel (1ll<>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<= 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<

【洛谷 P5056 【模板】插头dp】手写hash_table
代码
577ms
吸氧后 562ms
#include using namespace std; #define ll long longstruct 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])&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<= 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<

    推荐阅读