多条回路问题
/*********************************\
* @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,可以不需要管左右插头,遇到两个插头就合并,遇到空位置就新建即可。
*/
一条回路问题
/*******************************\
* @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 */
/*
将下面连通之后,就变成了简单回路问题。
*/
/****************************\
* @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 */
/*
简单回路问题。
注意读入数据,处理有点麻烦。
权值不在格点上,而在插头上。
*/
朴素:
/**************************************\
* @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 */
/*
行列倒置,将每一行转移到下一行的状态处理出来,然后矩阵乘法推到倒数第二行,最后一行单独转移。
*/
/****************************\
* @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了一次,读入数据写错了……
*/
简单路径问题
/************************************\
* @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) 只有一个独立插头。
要保证任何时候独立插头的个数不能超过两个。
*/
代码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类型。
*/
/*******************************\
* @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 */
/*
一道很简单的状压,不多说。
*/