【状态压缩】【动态规划】状压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 *//*一道很简单的状压,不多说。*/

原创粉丝点击