【状态压缩】【动态规划】状压DP复习

多条回路问题

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 */

/*

一道很简单的状压,不多说。

*/

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值