【状态压缩】【动态规划】状压DP复习
来源:互联网 发布:淘宝客建站平台 编辑:程序博客网 时间:2024/06/07 13:16
多条回路问题
hdu1693 Eat the Trees
/*********************************\ * @prob: hdu1693 Eat the Trees * * @auth: Wang Junji * * @stat: Accepted. * * @date: June, 19th, 2012 * * @memo: 插头DP *\*********************************/#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <string>typedef long long int64;const int maxN = 1 << 12, maxR = 20;struct Node{ int64 val[maxN]; int ID[maxN], cnt; unsigned S[maxN]; Node(): cnt(0) {memset(ID, 0xff, sizeof ID);} /* Node */ const int64& operator[](const int& Ind) {return val[Ind];} /* operator[] */ int64& operator[](const unsigned& __S) { if (ID[__S] == -1) val[ID[__S] = cnt++] = 0, S[ID[__S]] = __S; return val[ID[__S]]; } /* operator[] */ void clear() { for (int i = 0; i < cnt; ++i) ID[S[i]] = -1; cnt = 0; return; } /* clear */ const unsigned& status(const int& Ind) const {return S[Ind];} /* status */} f[2]; int mp[maxR][maxR], n, m;void readdata(){ scanf("%d%d", &n, &m); for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) scanf("%d", mp[i] + j); return;} /* readdata */const int64& work(){ int pst = 0, ths = 1; f[ths].clear(); f[ths][0U] = 1; for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) { std::swap(pst, ths); f[ths].clear(); unsigned p = m - j - 1; for (int k = 0; k < f[pst].cnt; ++k) { const int64& val = f[pst][k]; if (!val) continue; unsigned Last = f[pst].status(k); if (!j) { if (Last & 1U) continue; else Last >>= 1U; } /* if */ unsigned wp = (Last >> p) & 3U, Now = Last & ~(3U << p); if (!mp[i][j]) { if (!wp) f[ths][Now] += val; continue; } /* if */ if (!wp) f[ths][Now | (3U << p)] += val; else if (wp == 3) f[ths][Now] += val; else f[ths][Now | (1U << p)] += val, f[ths][Now | (2U << p)] += val; } /* for */ } /* for */ return f[ths][0U];} /* work */int main(){ freopen("tree.in", "r", stdin); freopen("tree.out", "w", stdout); int T = 0, Case = 0; scanf("%d", &T); while (T--) { readdata(); printf("Case %d: There are %lld ways", ++Case, work()); printf(" to eat the trees.\n"); } /* while */ return 0;} /* main *//*多条回路问题。最简单的插头DP,可以不需要管左右插头,遇到两个插头就合并,遇到空位置就新建即可。*/
一条回路问题
poj1739 Tony’s Tour
/*******************************\ * @prob: poj1739 Tony's Tour * * @auth: Wang Junji * * @stat: Accepted. * * @date: June. 19th. 2012 * * @memo: 插头DP *\*******************************/#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <string>typedef long long int64;const int maxN = 1 << 17, maxR = 20;struct Node{ int ID[maxN], cnt; int64 val[maxN]; unsigned S[maxN]; Node(): cnt(0) {memset(ID, 0xff, sizeof ID);} /* Node */ const int64& operator[](const int& Ind) {return val[Ind];} /* operator[] */ int64& operator[](const unsigned& __S) { if (ID[__S] == -1) val[ID[__S] = cnt++] = 0, S[ID[__S]] = __S; return val[ID[__S]]; } /* operator[] */ void clear() { for (int i = 0; i < cnt; ++i) ID[S[i]] = -1; cnt = 0; return; } /* clear */ const unsigned& status(const int& Ind) {return S[Ind];} /* status */} f[2]; bool mp[maxR][maxR]; int n, m;bool readdata(){ scanf("%d%d", &n, &m); if (!n || !m) return 0; for (int i = 0; i < n; ++i) { static char str[20]; scanf("%s", str); for (int j = 0; j < m; ++j) mp[i][j] = str[j] == '.'; } return 1;} /* readdata */inline unsigned Find(const unsigned& S, int pos, int delta){ int tmp = 0; for (int p = pos; p >= 0 && p <= m << 1; p += delta) { unsigned ths = (S >> p) & 3U; if (ths == 1U) ++tmp; if (ths == 2U) --tmp; if (!tmp) return p; } return unsigned(-1);} /* Find */const int64& work(){ int pst = 0, ths = 1; f[ths].clear(); f[ths][0U] = 1; for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) { std::swap(pst, ths); f[ths].clear(); int p = (m - j) << 1, q = p - 2; for (int k = 0; k < f[pst].cnt; ++k) { const int64& val = f[pst][k]; if (!val) continue; unsigned Last = f[pst].status(k); if (!j) { if (Last & 3U) continue; Last >>= 2U; } /* if */ unsigned wp = (Last >> p) & 3U, wq = (Last >> q) & 3U, Now = Last & ~(3U << p) & ~(3U << q); if (!mp[i][j]) { if (!wp && !wq) f[ths][Now] += val; continue; } /* if */ if (!wp && !wq) f[ths][Now | (1U << p) | (2U << q)] += val; else if (wp && wq) { if (wp == 1U && wq == 1U) f[ths][Now ^ (3U << Find(Last, q, -2))] += val; else if (wp == 2U && wq == 1U) f[ths][Now] += val; else if (wp == 2U && wq == 2U) f[ths][Now ^ (3U << Find(Last, p, 2))] += val; } /* if */ else f[ths][Last] += val, f[ths][Now | (wp << q) | (wq << p)] += val; } /* for */ } /* for */ return f[ths][8U | (1U << (m << 1))];} /* work */int main(){ freopen("tour.in", "r", stdin); freopen("tour.out", "w", stdout); while (readdata()) printf("%lld\n", work()); return 0;} /* main *//*将下面连通之后,就变成了简单回路问题。*/
hdu1964 Pipes
/****************************\ * @prob: hdu 1964 Pipes * * @auth: Wang Junji * * @stat: Accepted. * * @date: June. 19th, 2012 * * @memo: 插头DP *\****************************/#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <string>const int maxN = 1 << 21, maxR = 30, INF = 0x3f3f3f3f;struct Node{ int val[maxN], ID[maxN], cnt; unsigned S[maxN]; Node(): cnt(0) {memset(ID, 0xff, sizeof ID);} /* Node */ const int& operator[](const int& Ind) {return val[Ind];} /* operator[] */ int& operator[](const unsigned& __S) { if (ID[__S] == -1) val[ID[__S] = cnt++] = INF, S[ID[__S]] = __S; return val[ID[__S]]; } /* operator[] */ void clear() { for (int i = 0; i < cnt; ++i) ID[S[i]] = -1; cnt = 0; return; } /* clear */ const unsigned& status(const int& Ind) {return S[Ind];} /* status */} f[2]; int right[maxR][maxR], down[maxR][maxR], n, m;bool readdata(){ scanf("%d%d\n", &n, &m); for (int j = 0; j <= m << 1; ++j) scanf("#"); for (int i = 0; i < n; ++i) { scanf("\n#"); for (int j = 0; j < m - 1; ++j) scanf("%d", right[i] + j); scanf(" #\n#"); if (i < n - 1) for (int j = 0; j < m; ++j) scanf("%d#", down[i] + j); } /* for */ scanf(" #\n"); for (int j = 0; j <= m << 1; ++j) scanf("#"); return 1;} /* readdata */inline unsigned Find(const unsigned& S, int pos, int delta){ int tmp = 0; for (int p = pos; p >= 0 && p <= m << 1; p += delta) { unsigned ths = (S >> p) & 3U; if (ths == 1U) ++tmp; if (ths == 2U) --tmp; if (!tmp) return p; } return unsigned(-1);} /* Find */inline int& gmin(int& a, const int& b) {return a < b ? a : (a = b);} /* gmin */int work(){ int pst = 0, ths = 1; f[ths].clear(); f[ths][0U] = 0; for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) { std::swap(pst, ths); f[ths].clear(); unsigned p = (m - j) << 1, q = p - 2; for (int k = 0; k < f[pst].cnt; ++k) { int val = f[pst][k], valr = val + right[i][j], vald = val + down[i][j], valrd = valr + vald - val; if (val == INF) continue; unsigned Last = f[pst].status(k); if (!j) { if (Last & 3U) continue; Last >>= 2U; } unsigned wp = (Last >> p) & 3U, wq = (Last >> q) & 3U, Now = Last & ~(3U << p) & ~(3U << q); if (!wp && !wq) gmin(f[ths][Now | (1U << p) | (2U << q)], valrd); else if (wp && wq) { if (wp == 1U && wq == 1U) gmin(f[ths][Now ^ (3U << Find(Last, q, -2))], val); else if (wp == 1U && wq == 2U) i == n - 1 && j == m - 1 ? gmin(f[ths][Now], val) : 0; else if (wp == 2U && wq == 1U) gmin(f[ths][Now], val); else if (wp == 2U && wq == 2U) gmin(f[ths][Now ^ (3U << Find(Last, p, 2))], val); } /* if */ else { if (wp && i < n - 1) gmin(f[ths][Last], vald); if (wq && j < m - 1) gmin(f[ths][Last], valr); if (wp && j < m - 1) gmin(f[ths][Now | (wp << q) | (wq << p)], valr); if (wq && i < n - 1) gmin(f[ths][Now | (wp << q) | (wq << p)], vald); } /* else */ } /* for */ } /* for */ return f[ths][0U];} /* work */int main(){ freopen("pipe.in", "r", stdin); freopen("pipe.out", "w", stdout); int T = 0; scanf("%d", &T); while (T--) readdata(), printf("%d\n", work()); return 0;} /* main *//*简单回路问题。注意读入数据,处理有点麻烦。权值不在格点上,而在插头上。*/
zju3256 Tour in the Castle
朴素:
/**************************************\ * @prob: zoj3256 Tour in the Castle * * @auth: Wang Junji * * @stat: Time Limit Exceeded. * * @date: June. 18th, 2012 * * @memo: 插头DP *\**************************************/#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <string>const int maxN = 1 << 16, MOD = 7777777;struct Node{ int val[maxN], ID[maxN], cnt; unsigned S[maxN]; Node(): cnt(0) {memset(ID, 0xff, sizeof ID);} /* Node */ const int& operator[](const int& Ind) {return val[Ind];} /* operator[] */ int& operator[](const unsigned& __S) { if (ID[__S] == -1) val[ID[__S] = cnt++] = 0, S[ID[__S]] = __S; return val[ID[__S]]; } /* operator[] */ const unsigned& status(const int& Ind) const {return S[Ind];} /* status */ void clear() { for (int i = 0; i < cnt; ++i) ID[S[i]] = -1; cnt = 0; return; } /* clear */} f[2]; int n, m;inline unsigned Find(const unsigned& S, const unsigned& pos, int delta){ int tmp = 0; for (int p = pos; p >= 0 && p <= m << 1; p += delta) { unsigned ths = (S >> p) & 3U; if (ths == 1U) ++tmp; if (ths == 2U) --tmp; if (!tmp) return p; } /* for */ // return (unsigned)-1;} /* Find */inline int& Add(int& a, const int& b){return (a += b) >= MOD ? (a -= MOD) : a;}/* Add */int work(){ int pst = 0, ths = 1; f[ths].clear(); f[ths][(2U | (1U << ((m - 1) << 1U))) << 2U] = 1; for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) { std::swap(pst, ths); f[ths].clear(); int p = (m - j) << 1, q = p - 2; for (int k = 0; k < f[pst].cnt; ++k) { const int& val = f[pst][k]; if (!val) continue; unsigned Last = f[pst].status(k); if (!j) { if (Last & 3U) continue; Last >>= 2; } unsigned wp = (Last >> p) & 3U, wq = (Last >> q) & 3U, Now = Last & ~(3U << p) & ~(3U << q); if (!wp && !wq) i < n - 1 && j < m - 1 ? Add(f[ths][Now | (1U << p) | (2U << q)], val) : 0; else if (wp == 1U && wq == 2U) j == m - 1 && i == n - 1 ? Add(f[ths][Now], val) : 0; else if (wp == 2U && wq == 1U) Add(f[ths][Now], val); else if (wp == 1U && wq == 1U) Add(f[ths][Now ^ (3U << Find(Last, q, -2))], val); else if (wp == 2U && wq == 2U) Add(f[ths][Now ^ (3U << Find(Last, p, 2))], val); else { if ((!wp && wq && j < m - 1) || (wp && !wq && i < n - 1)) Add(f[ths][Last], val); if ((wp && !wq && j < m - 1) || (!wp && wq && i < n - 1)) Add(f[ths][Now | (wp << q) | (wq << p)], val); } /* else */ } /* for */ } /* for */ return f[ths][0U];} /* work */int main(){ freopen("tour.in", "r", stdin); freopen("tour.out", "w", stdout); while (scanf("%d%d", &m, &n) != EOF) { int ans = work(); if (ans) printf("%d\n", ans); else printf("Impossible\n"); } /* while */ return 0;} /* main *//*将左下角和左上角相连过后,问题便变成了Formula 1。朴素的插头DP要超时,需要用矩阵乘法优化。*/
矩阵乘法优化:
/**************************************\ * @prob: zoj3256 Tour in the Castle * * @auth: Wang Junji * * @stat: Accepted. * * @date: June. 19th, 2012 * * @memo: 插头DP *\**************************************/#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <string>#include <ctime>const int maxN = 1 << 16, MOD = 7777777;struct Node{ int val[maxN], ID[maxN], cnt; unsigned S[maxN]; Node(): cnt(0) {memset(ID, 0xff, sizeof ID);} /* Node */ const int& operator[](const int& Ind) {return val[Ind];} /* operator[] */ int& operator[](const unsigned& __S) { if (ID[__S] == -1) val[ID[__S] = cnt++] = 0, S[ID[__S]] = __S; return val[ID[__S]]; } /* operator[] */ const unsigned& status(const int& Ind) const {return S[Ind];} /* status */ void clear() { for (int i = 0; i < cnt; ++i) ID[S[i]] = -1; cnt = 0; return; } /* clear */} f[10]; int ID[maxN], n, m, cnt; unsigned status[maxN];struct Matrix{ int ele[130][130]; Matrix() {memset(ele, 0, sizeof ele);} /* Matrix */ Matrix(const Matrix& b) {memcpy(ele, b.ele, sizeof ele);} /* Matrix */ int* const operator[](const int& Ind) {return ele[Ind];} const int* const operator[](const int& Ind) const {return ele[Ind];} Matrix& operator=(const Matrix& b) {memcpy(ele, b.ele, sizeof ele); return *this;} /* operator= */ Matrix& operator*=(const Matrix& b) { Matrix ans; for (int i = 0; i < cnt; ++i) for (int j = 0; j < cnt; ++j) { long long tmp = 0; for (int k = 0; k < cnt; ++k) tmp += (long long)ele[i][k] * b[k][j]; //累积到平方才取余。 ans[i][j] = tmp % MOD; } /* for */ return *this = ans; } /* operator*= */ void clear() {memset(ele, 0, sizeof ele); return;} /* clear */} g;inline unsigned Find(const unsigned& S, const unsigned& pos, int delta){ int tmp = 0; for (int p = pos; p >= 0 && p <= m << 1; p += delta) { unsigned ths = (S >> p) & 3U; if (ths == 1U) ++tmp; if (ths == 2U) --tmp; if (!tmp) return p; } /* for */ // return (unsigned)-1;} /* Find */inline int& Add(int& a, const int& b){return (a += b) >= MOD ? (a -= MOD) : a;}/* Add */void work(const unsigned& __S, bool flag){ if (!flag) f[0].clear(), f[0][__S] = 1; for (int j = 0; j < m; ++j) { f[j + 1].clear(); int p = (m - j) << 1, q = p - 2; for (int k = 0; k < f[j].cnt; ++k) { const int& val = f[j][k]; if (!val) continue; unsigned Last = f[j].status(k), wp = (Last >> p) & 3U, wq = (Last >> q) & 3U, Now = Last & ~(3U << p) & ~(3U << q); if (!wp && !wq) !flag && j < m - 1 ? Add(f[j + 1][Now | (1U << p) | (2U << q)], val) : 0; else if (wp == 1U && wq == 2U) flag && j == m - 1 ? Add(f[j + 1][Now], val) : 0; else if (wp == 2U && wq == 1U) Add(f[j + 1][Now], val); else if (wp == 1U && wq == 1U) Add(f[j + 1][Now ^ (3U << Find(Last, q, -2))], val); else if (wp == 2U && wq == 2U) Add(f[j + 1][Now ^ (3U << Find(Last, p, 2))], val); else { if ((!wp && wq && j < m - 1) || (wp && !wq)) Add(f[j + 1][Last], val); if ((wp && !wq && j < m - 1) || (!wp && wq)) Add(f[j + 1][Now | (wp << q) | (wq << p)], val); } /* else */ } /* for */ } /* for */ if (!flag) { bool flag = 0; for (int k = 0; k < f[m].cnt; ++k) if (f[m][k]) {flag = 1; break;} if (!flag) return; for (int k = 0; k < f[m].cnt; ++k) { unsigned S = f[m].status(k); if (S & 3U) continue; S >>= 2U; if (!S) continue; if (ID[S] == -1) status[ID[S] = cnt++] = S; if (ID[__S] == -1) status[ID[__S] = cnt++] = __S; g[ID[__S]][ID[S]] = f[m][k]; } /* for */ } /* if */ return;} /* work */inline Matrix& pow(Matrix& g, const int& __n){ Matrix tmp = g, ans; for (int i = 0; i < cnt; ++i) ans[i][i] = 1; for (int n = __n; n; n >>= 1, tmp *= tmp) if (n & 1) ans *= tmp; return g = ans;} /* pow */inline bool valid(const unsigned &__S){ int tmp = 0; for (int p = 0; p <= m << 1; ++++p) { unsigned ths = (__S >> p) & 3U; if (ths == 1U) ++tmp; if (ths == 2U) --tmp; if (ths == 3U) return 0; if (tmp > 0) return 0; } return !tmp;} /* valid */int main(){ freopen("tour.in", "r", stdin); freopen("tour.out", "w", stdout); memset(ID, 0xff, sizeof ID); while (scanf("%d%d", &m, &n) != EOF) { for (int i = 0; i < cnt; ++i) ID[status[i]] = -1; cnt = 0; g.clear(); for (unsigned S = 6U; S < 1U << (m << 1); ++++S) if (valid(S)) work(S, 0); pow(g, n - 1); f[0].clear(); int i = ID[2U | (1U << ((m - 1) << 1))]; for (int j = 0; j < cnt; ++j) f[0][status[j]] = g[i][j]; work(0, 1); int ans = f[m][0U]; if (ans) printf("%d\n", ans); else printf("Impossible\n"); } /* while */ return 0;} /* main *//*行列倒置,将每一行转移到下一行的状态处理出来,然后矩阵乘法推到倒数第二行,最后一行单独转移。*/
hdu3377 Plan
/****************************\ * @prob: hdu3377 Plan * * @auth: Wang Junji * * @stat: Accepted. * * @date: June. 19th, 2012 * * @memo: 插头DP *\****************************/#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <string>const int maxN = 1 << 18, maxR = 20, INF = 0x3f3f3f3f;struct Node{ int val[maxN], ID[maxN], cnt; unsigned S[maxN]; Node(): cnt(0) {memset(ID, 0xff, sizeof ID);} /* Node */ const int& operator[](const int& Ind) {return val[Ind];} /* operator[] */ int& operator[](const unsigned& __S) { if (ID[__S] == -1) val[ID[__S] = cnt++] = ~INF, S[ID[__S]] = __S; return val[ID[__S]]; } /* operator[] */ void clear() { for (int i = 0; i < cnt; ++i) ID[S[i]] = -1; cnt = 0; return; } /* clear */ const unsigned& status(const int& Ind) {return S[Ind];} /* status */} f[2]; int mp[maxR][maxR], n, m;bool readdata(){ if (scanf("%d%d", &m, &n) == EOF) return 0; for (int i = 0; i < m; ++i) for (int j = 0; j < n; ++j) scanf("%d", mp[j] + i); return 1;} /* readdata */inline unsigned Find(const unsigned& S, int pos, int delta){ int tmp = 0; for (int p = pos; p >= 0 && p <= m << 1; p += delta) { unsigned ths = (S >> p) & 3U; if (ths == 1U) ++tmp; if (ths == 2U) --tmp; if (!tmp) return p; } return unsigned(-1);} /* Find */inline int& gmax(int& a, const int& b) {return a > b ? a : (a = b);} /* gmax */int work(){ int pst = 0, ths = 1; f[ths].clear(); f[ths][3U << (m << 1)] = 0; for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) { std::swap(pst, ths); f[ths].clear(); unsigned p = (m - j) << 1, q = p - 2; for (int k = 0; k < f[pst].cnt; ++k) { const int& val = f[pst][k], nval = val + mp[i][j]; unsigned Last = f[pst].status(k); if (!j) { if (Last & 3U) continue; Last >>= 2U; } /* if */ unsigned wp = (Last >> p) & 3U, wq = (Last >> q) & 3U, Now = Last & ~(3U << p) & ~(3U << q); if (!wp && !wq) gmax(f[ths][Now], val), gmax(f[ths][Now | (1U << p) | (2U << q)], nval); else if (wp && wq) { if (wp == 1U && wq == 1U) gmax(f[ths][Now ^ (3U << Find(Last, q, -2))], nval); else if (wp == 1U && wq == 3U) gmax(f[ths][Now | (3U << Find(Last, p, -2))], nval); else if (wp == 2U && wq == 1U) gmax(f[ths][Now], nval); else if (wp == 2U && wq == 2U) gmax(f[ths][Now ^ (3U << Find(Last, p, 2))], nval); else if (wp == 2U && wq == 3U) gmax(f[ths][Now | (3U << Find(Last, p, 2))], nval); else if (wp == 3U && wq == 1U) gmax(f[ths][Now | (3U << Find(Last, q, -2))], nval); else if (wp == 3U && wq == 2U) gmax(f[ths][Now | (3U << Find(Last, q, 2))], nval); } /* if */ else gmax(f[ths][Last], nval), gmax(f[ths][Now | (wp << q) | (wq << p)], nval); } /* for */ } /* for */ return f[ths][0xcU];} /* work */int main(){ freopen("plan.in", "r", stdin); freopen("plan.out", "w", stdout); int Case = 0; while (readdata()) printf("Case %d: %d\n", ++Case, work()); return 0;} /* main *//*注意从起点处出发的和到终点处结束的为独立插头,所以转移的时候要考虑独立插头。Wrong Answer了一次,读入数据写错了……*/
简单路径问题
zju3213 Beautifal Meadow
/************************************\ * @prob: zoj3213 Beautiful Meadow * * @auth: Wang Junji * * @stat: Accepted. * * @date: June. 19th, 2012 * * @memo: 插头DP *\************************************/#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <string>const int maxN = 1 << 18, maxR = 20;struct Node{ int val[maxN], ID[maxN], cnt; unsigned S[maxN]; Node(): cnt(0) {memset(ID, 0xff, sizeof ID);} /* Node */ const int& operator[](const int& Ind) {return val[Ind];} /* operator[] */ int& operator[](const unsigned& __S) { if (ID[__S] == -1) val[ID[__S] = cnt++] = 0, S[ID[__S]] = __S; return val[ID[__S]]; } /* operator[] */ void clear() { for (int i = 0; i < cnt; ++i) ID[S[i]] = -1; cnt = 0; return; } /* clear */ const unsigned& status(const int& Ind) {return S[Ind];}} f[2]; int mp[maxR][maxR], n, m, T;void readdata(){ scanf("%d%d", &n, &m); for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) scanf("%d", mp[i] + j); return;} /* readdata */inline int& gmax(int& a, const int& b) {return a > b ? a : (a = b);} /* gmax */inline unsigned Find(const unsigned& S, int pos, int delta){ int tmp = 0; for (int p = pos; p >= 0 && p <= m << 1; p += delta) { const unsigned& ths = (S >> p) & 3U; if (ths == 1U) ++tmp; if (ths == 2U) --tmp; if (!tmp) return p; } /* for */ return unsigned(-1);} /* Find */inline bool valid(const unsigned& __S){ int cnt = 0; for (unsigned S = __S; S; S >>= 2) if ((S & 3U) == 3U && ++cnt > 2) return 0; return 1;} /* valid */int work(){ int pst = 0, ths = 1, ans = 0; f[ths].clear(); f[ths][0U] = 0; for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) { gmax(ans, mp[i][j]); std::swap(pst, ths); f[ths].clear(); unsigned p = (m - j) << 1, q = p - 2; for (int k = 0; k < f[pst].cnt; ++k) { const int& val = f[pst][k], nval = val + mp[i][j]; unsigned Last = f[pst].status(k); if (!valid(Last)) continue; if (!j) { if (Last & 3U) continue; Last >>= 2; } /* if */ unsigned wp = (Last >> p) & 3U, wq = (Last >> q) & 3U, Now = Last & ~(3U << p) & ~(3U << q); if (!mp[i][j]) { if (!wp && !wq) gmax(f[ths][Now], val); continue; } /* if */ if (!wp && !wq) { gmax(f[ths][Now], val); if (i < n - 1 && mp[i + 1][j]) gmax(f[ths][Now | (3U << p)], nval); if (j < m - 1 && mp[i][j + 1]) gmax(f[ths][Now | (3U << q)], nval); if (i < n - 1 && j < m - 1 && mp[i + 1][j] && mp[i][j + 1]) gmax(f[ths][Now | (1U << p) | (2U << q)], nval); } /* if */ else if (wp && wq) { if (wp == 1U && wq == 2U) Now ? 0 : gmax(ans, nval); else if (wp == 2U && wq == 1U) gmax(f[ths][Now], nval); else if (wp == 1U && wq == 1U) gmax(f[ths][Now ^ (3U << Find(Last, q, -2))], nval); else if (wp == 2U && wq == 2U) gmax(f[ths][Now ^ (3U << Find(Last, p, 2))], nval); else if (wp == 3U && wq == 3U) Now ? 0 : gmax(ans, nval); else if (wp == 1U && wq == 3U) gmax(f[ths][Now | (3U << Find(Last, p, -2))], nval); else if (wp == 2U && wq == 3U) gmax(f[ths][Now | (3U << Find(Last, p, 2))], nval); else if (wq == 1U && wp == 3U) gmax(f[ths][Now | (3U << Find(Last, q, -2))], nval); else if (wq == 2U && wp == 3U) gmax(f[ths][Now | (3U << Find(Last, q, 2))], nval); } /* if */ else { if ((wp && i < n - 1 && mp[i + 1][j]) || (wq && j < m - 1 && mp[i][j + 1])) gmax(f[ths][Last], nval); if ((wq && i < n - 1 && mp[i + 1][j]) || (wp && j < m - 1 && mp[i][j + 1])) gmax(f[ths][Now | (wp << q) | (wq << p)], nval); if (wp == 3U || wq == 3U) Now ? 0 : gmax(ans, nval); else if (wp == 1U) gmax(f[ths][Now | (3U << Find(Last, p, -2))], nval); else if (wp == 2U) gmax(f[ths][Now | (3U << Find(Last, p, 2))], nval); else if (wq == 1U) gmax(f[ths][Now | (3U << Find(Last, q, -2))], nval); else if (wq == 2U) gmax(f[ths][Now | (3U << Find(Last, q, 2))], nval); } /* else */ } /* for */ } /* for */ return gmax(ans, f[ths][0U]);} /* work */int main(){ freopen("meadow.in", "r", stdin); freopen("meadow.out", "w", stdout); scanf("%d", &T); while (T--) readdata(), printf("%d\n", work()); return 0;} /* main *//*简单路径问题。要注意几个结束转移的条件(这时候其它位置不能有插头): 1) 两个独立插头相遇; 2) 左括号插头和右括号插头相遇; 3) 只有一个独立插头。要保证任何时候独立插头的个数不能超过两个。*/
poj3133 manhattan wiring
代码1:
/************************************\ * @prob: poj3133 Manhattan Wiring * * @auth: Wang Junji * * @stat: Accepted. * * @date: June. 17th, 2012 * * @memo: 插头DP *\************************************/#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <string>const int maxN = 1 << 20, maxR = 20, INF = 0x3f3f3f3f;struct Node{ int len[maxN], ID[maxN], cnt; unsigned S[maxN]; Node(): cnt(0) {memset(ID, 0xff, sizeof ID);} /* Node */ const int& operator[](const int& Ind) {return len[Ind];} /* operator[] */ int& operator[](const unsigned& __S) { if (ID[__S] == -1) len[ID[__S] = cnt++] = INF, S[ID[__S]] = __S; return len[ID[__S]]; } /* operator[] */ void clear() { for (int i = 0; i < cnt; ++i) ID[S[i]] = -1; cnt = 0; return; } /* clear */ const unsigned& status(const int& Ind) const {return S[Ind];} /* status */} f[2]; int mp[maxR][maxR], n, m;void init_file(){ freopen("Wiring.in", "r", stdin); freopen("Wiring.out", "w", stdout); return;} /* init_file */bool readdata(){ if (scanf("%d%d", &n, &m) == EOF) return 0; if (!n || !m) return 0; for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) scanf("%d", mp[i] + j); return 1;} /* readdata */template <typename _Tp>inline _Tp& gmin(_Tp& a, const _Tp& b) {return a < b ? a : (a = b);}/* gmin */void work(){ int pst = 0, ths = 1; f[ths].clear(); f[ths][0U] = 0; for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) { std::swap(pst, ths); f[ths].clear(); unsigned p = (m - j) << 1, q = p - 2; for (int k = 0; k < f[pst].cnt; ++k) { const int& len = f[pst][k]; unsigned Last = f[pst].status(k); if (!j) { if (Last & 3U) continue; Last >>= 2U; } /* if */ unsigned wp = (Last >> p) & 3U, wq = (Last >> q) & 3U, Now = Last & ~(3U << p) & ~(3U << q); if ((wp | wq) == 3U) continue; if (mp[i][j] == 1) { if (!wp && !wq) gmin(f[ths][Now], len); continue; } /* if */ else if (mp[i][j] == 2) { if (!wp && !wq) gmin(f[ths][Now | (1U << p)], len), gmin(f[ths][Now | (1U << q)], len); else if ((!wp && wq == 1U) || (wp == 1U && !wq)) gmin(f[ths][Now], len); } /* if */ else if (mp[i][j] == 3) { if (!wp && !wq) gmin(f[ths][Now | (2U << p)], len), gmin(f[ths][Now | (2U << q)], len); else if ((!wp && wq == 2U) || (wp == 2U && !wq)) gmin(f[ths][Now], len); } /* if */ else { if (!wp && !wq) gmin(f[ths][Now | (1U << p) | (1U << q)], len + 1), gmin(f[ths][Now | (2U << p) | (2U << q)], len + 1), gmin(f[ths][Now], len); else if (wp && wq) gmin(f[ths][Now], len + 1); else gmin(f[ths][Last], len + 1), gmin(f[ths][Now | (wp << q) | (wq << p)], len + 1); } /* else */ } /* for */ } /* for */ int ans = f[ths][0U] + 2; if (ans > INF) ans = 0; printf("%d\n", ans); return;} /* work */int main(){ init_file(); while (readdata()) work(); return 0;} /* main *//*用一个四进制数表示每个插头。1:一个和2相连的插头;2:一个和3相连的插头。那么将所有插头的直走、转弯、以及完结考虑完即可。清零的时候没注意有很多不必要的情况,所以导致超时,改正后已通过。*/
代码2:
/************************************\ * @prob: poj3133 Manhattan Wiring * * @auth: Wang Junji * * @stat: Accepted. * * @date: June. 17th, 2012 * * @memo: 插头DP *\************************************/#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <string>const int maxN = 1 << 20, maxR = 20, INF = 0x3f3f3f3f;struct Node{ int len[maxN], ID[maxN], cnt; unsigned S[maxN]; Node(): cnt(0) {memset(ID, 0xff, sizeof ID);} /* Node */ const int& operator[](const int& Ind) {return len[Ind];} /* operator[] */ int& operator[](const unsigned& __S) { if (ID[__S] == -1) len[ID[__S] = cnt++] = INF, S[ID[__S]] = __S; return len[ID[__S]]; } /* operator[] */ void clear() { for (int i = 0; i < cnt; ++i) ID[S[i]] = -1; cnt = 0; return; } /* clear */ const unsigned& status(const int& Ind) const {return S[Ind];} /* status */} f[2]; int mp[maxR][maxR], n, m;void init_file(){ freopen("Wiring.in", "r", stdin); freopen("Wiring.out", "w", stdout); return;} /* init_file */bool readdata(){ if (scanf("%d%d", &n, &m) == EOF) return 0; if (!n || !m) return 0; for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) scanf("%d", mp[i] + j); return 1;} /* readdata */template <typename _Tp>inline _Tp& gmin(_Tp& a, const _Tp& b) {return a < b ? a : (a = b);}/* gmin */void work(){ int pst = 0, ths = 1; f[ths].clear(); f[ths][0U] = 0; for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) { std::swap(pst, ths); f[ths].clear(); unsigned p = (m - j) << 1, q = p - 2; for (int k = 0; k < f[pst].cnt; ++k) { const int& len = f[pst][k]; unsigned Last = f[pst].status(k); if (!j) { if (Last & 3U) continue; Last >>= 2U; } /* if */ unsigned wp = (Last >> p) & 3U, wq = (Last >> q) & 3U, Now = Last & ~(3U << p) & ~(3U << q); if ((wp | wq) == 3U) continue; if (mp[i][j] == 1) { if (!wp && !wq) gmin(f[ths][Now], len); continue; } /* if */ else if (mp[i][j] == 2) { if (!wp && !wq) { if (i < n - 1 && mp[i + 1][j] != 1 && mp[i + 1][j] != 3) gmin(f[ths][Now | (1U << p)], len); if (j < m - 1 && mp[i][j + 1] != 1 && mp[i][j + 1] != 3) gmin(f[ths][Now | (1U << q)], len); } /* if */ else if ((!wp && wq == 1U) || (wp == 1U && !wq)) gmin(f[ths][Now], len); } /* if */ else if (mp[i][j] == 3) { if (!wp && !wq) { if (i < n - 1 && mp[i + 1][j] != 1 && mp[i + 1][j] != 2) gmin(f[ths][Now | (2U << p)], len); if (j < m - 1 && mp[i][j + 1] != 1 && mp[i][j + 1] != 2) gmin(f[ths][Now | (2U << q)], len); } /* if */ else if ((!wp && wq == 2U) || (wp == 2U && !wq)) gmin(f[ths][Now], len); } /* if */ else { if (!wp && !wq) { gmin(f[ths][Now], len); if (i < n - 1 && j < m - 1 && mp[i + 1][j] != 1 && mp[i][j + 1] != 1) { if (mp[i + 1][j] != 3 && mp[i][j + 1] != 3) gmin(f[ths][Now | (1U << p) | (1U << q)], len + 1); if (mp[i + 1][j] != 2 && mp[i][j + 1] != 2) gmin(f[ths][Now | (2U << p) | (2U << q)], len + 1); } /* if */ } /* if */ else if (wp && wq) gmin(f[ths][Now], len + 1); else { if ((wp && !wq && i < n - 1 && mp[i + 1][j] != 1 && ((wp == 1U && mp[i + 1][j] != 3) || (wp == 2U && mp[i + 1][j] != 2))) || (!wp && wq && j < m - 1 && mp[i][j + 1] != 1 && ((wq == 1U && mp[i][j + 1] != 3) || (wq == 2U && mp[i][j + 1] != 2)))) gmin(f[ths][Last], len + 1); if ((wq && !wp && i < n - 1 && mp[i + 1][j] != 1 && ((wq == 1U && mp[i + 1][j] != 3) || (wq == 2U && mp[i + 1][j] != 2))) || (!wq && wp && j < m - 1 && mp[i][j + 1] != 1 && ((wp == 1U && mp[i][j + 1] != 3) || (wp == 2U && mp[i][j + 1] != 2)))) gmin(f[ths][Now | (wp << q) | (wq << p)], len + 1); } /* else */ } /* else */ } /* for */ } /* for */ int ans = f[ths][0U] + 2; if (ans > INF) ans = 0; printf("%d\n", ans); return;} /* work */int main(){ init_file(); while (readdata()) work(); return 0;} /* main *//*将一些转移作了特殊判断,可以使转移更快。*/
其它状压类型
poj2411 Mondriaan's Dream
/*************************************\ * @prob: poj2411 Mondriaan's Dream * * @auth: Wang Junji * * @stat: Accepted. * * @date: June. 17th, 2012 * * @memo: 状态压缩型动态规划 *\*************************************/#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <string>const int maxN = 1 << 11, maxR = 20;typedef long long int64;struct Node{ int64 val[maxN]; int ID[maxN], cnt; unsigned S[maxN]; Node(): cnt(0) {memset(ID, 0xff, sizeof ID);} /* Node */ const int64& operator[](const int& Ind) {return val[Ind];} /* operator[] */ int64& operator[](const unsigned& __S) { if (ID[__S] == -1) val[ID[__S] = cnt++] = 0, S[ID[__S]] = __S; return val[ID[__S]]; } /* operator[] */ void clear() {cnt = 0; memset(ID, 0xff, sizeof ID);} /* clear */ const unsigned& status(const int& Ind) const {return S[Ind];} /* status */} f[2]; int n, m;void init(){ freopen("Dream.in", "r", stdin); freopen("Dream.out", "w", stdout); return;} /* init */template <typename _Tp>inline _Tp& Add(_Tp& a, const _Tp& b) {return a += b;} /* Add */void work(){ int pst = 0, ths = 1; f[ths].clear(); f[ths][0U] = 1; for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) { std::swap(pst, ths); f[ths].clear(); unsigned p = m - j - 1; for (int k = 0; k < f[pst].cnt; ++k) { const int64& val = f[pst][k]; const unsigned& Last = f[pst].status(k); if (!((Last >> p) & 1U) && i) { Add(f[ths][Last | (1U << p)], val); continue; } /* if */ if (!((Last >> p) & 2U) && j) Add(f[ths][Last | (3U << p)], val); Add(f[ths][Last & ~(1U << p)], val); } /* for */ } /* for */ printf("%lld\n", Add(f[ths][(1U << m) - 1], 0LL)); return;} /* work */int main(){ init(); while (scanf("%d%d", &n, &m) != EOF && n && m) work(); return 0;} /* main *//*要保证铺满。要用long long类型。*/
poj3254 Corn Fields
/*******************************\ * @prob: poj3254 Corn Fields * * @auth: Wang Junji * * @stat: Accepted. * * @date: June. 17th, 2012 * * @memo: 状态压缩型动态规划 *\*******************************/#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <string>const int maxR = 20, maxN = 1 << 12, MOD = 100000000;struct Node{ int val[maxN], ID[maxN], cnt; unsigned S[maxN]; Node(): cnt(0) {memset(ID, 0xff, sizeof ID);} /* Node */ const int& operator[](const int& Index) {return val[Index];} /* operator[] */ int& operator[](const unsigned& __S) { if (ID[__S] == -1) val[ID[__S] = cnt++] = 0, S[ID[__S]] = __S; return val[ID[__S]]; } /* operator[] */ void clear() {memset(ID, 0xff, sizeof ID); cnt = 0; return;} /* clear */ const unsigned& status(const int& Index) const {return S[Index];} /* status */} f[2]; bool mp[maxR][maxR]; int n, m;void init(){ freopen("Corn_Fields.in", "r", stdin); freopen("Corn_Fields.out", "w", stdout); scanf("%d%d", &n, &m); for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) scanf("%d", mp[i] + j); return;} /* init */inline int& Add(int& a, const int& b){return ((a += b) >= MOD) ? (a -= MOD) : a;}/* Add */void work(){ int pst = 0, ths = 1; f[ths][0U] = 1; for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) { std::swap(pst, ths); f[ths].clear(); unsigned p = m - j - 1; for (int k = 0; k < f[pst].cnt; ++k) { const int& val = f[pst][k]; const unsigned& Last = f[pst].status(k); Add(f[ths][Last & ~(1U << p)], val); if (!((Last >> p) & 3U) && mp[i][j]) Add(f[ths][Last | (1U << p)], val); } /* for */ } /* for */ int ans = 0; for (int k = 0; k < f[ths].cnt; ++k) Add(ans, f[ths][k]); printf("%d\n", ans); return;} /* work */int main(){ init(); work(); return 0;} /* main *//*一道很简单的状压,不多说。*/
- 【状态压缩】【动态规划】状压DP复习
- 动态规划之状态压缩dp入门
- sdoi2009 [动态规划 状态压缩DP] 学校食堂
- 动态规划之状态压缩dp入门
- 动态规划之状态压缩dp入门
- 动态规划专题:树上DP和状态压缩DP
- 状态压缩动态规划
- 状态压缩动态规划
- 状态压缩动态规划
- 状态压缩动态规划
- 状态压缩动态规划
- 动态规划!状态压缩
- 状态压缩动态规划
- 动态规划(状态压缩dp) --- HDU 1074 **
- uva 11825 Hackers' Crackdown(动态规划-状态压缩DP)
- 【动态规划】【状态压缩DP】[UVa 1354]Mobile Computing
- 动态规划解TSP问题(状态压缩dp)
- 【状态压缩】【动态规划】电子竞技
- gsl 的gsl_rng_mt19937 error问题 gsl_rng_alloc()
- poj 2562 Primary Arithmetic
- JSON
- iOS NSOperationQueue的使用
- WPF学习
- 【状态压缩】【动态规划】状压DP复习
- 修改testlink使其适应大数据量
- android 设置progressbar的背景颜色
- 分享舍得网开发过程
- windows服务的撰写方法
- VS中的路径宏 vc++中OutDir、ProjectDir、SolutionDir各种路径
- Oracle.apps.fnd.cp.request包常用java类分析
- 设计模式笔记21:中介者模式(Mediator Pattern)
- hibernate如何实现延迟加载