Ural 1519. Formula 1 优美的插头DP

今天早上学了插头DP的思想和最基础的应用,中午就开始敲了,岐哥说第一次写不要看别人代码,利用自己的理解一点点得写出来,这样才锻炼代码能力!于是下午慢慢地构思轮廓,一点点地敲出主体代码,其实是很磨蹭的,由于要考虑好多东西,而且昨晚2点睡的有点困,最后终于磨蹭出来了,第一次的代码搓没关系,自己写的才重要。然后果然不出我所料,调试到了晚上才A了(一个郁闷的错误)。。。A的感觉真的是爽呀,虽然搞了差不多一天。当然自己写了自己想的代码后也要把代码优化,不然队友看不懂自己代码就囧了。。。


插头DP,建议大家想学的好好看看陈丹琦的国家集训队论文,这是个优美的DP。

http://www.docin.com/p-46797997.html


 

#include <stdio.h>

#include <string.h>



#define LL __int64



const int mod = 10007;



//   哈希表

struct HASH{

    int head[mod+10], E, next[80000];

    LL val[80000], cnt[80000];



    void init() {

        memset(head, -1, sizeof(head));

        E = 0;

    }



    int findhash(LL x) {

        return (x%mod + mod)%mod;

    }



    void add(LL x, LL sum) {

        int u = findhash(x);

        for(int i = head[u];i != -1;i = next[i]) if(val[i] == x) {

            cnt[i] += sum;

            return ;

        }

        val[E] = x;

        cnt[E] = sum;

        next[E] = head[u];

        head[u] = E++;

    }



}biao1, biao2;



int c[22], n, m, d[22];

//  编码

void get(LL x) {

    for(int i = m+1;i >= 1; i--) {

        c[i] = x&7;

        x /= 8;

    }

}

//  解码

LL getval() {

    LL ret = 0;

    for(int i = 1;i <= m+1; i++) {

        ret |= d[i];

        ret *= 8;

    }

    ret /= 8;

    return ret ;

}

//   转化成最小表示法

void change() {

    int vis[22];

    memset(vis, 0, sizeof(vis));

    int num = 1;

    for(int i = 1;i <= m+1;i ++) {

        if(!d[i])   continue;

        if(!vis[d[i]]) {

            vis[d[i]] = num;

            d[i] = num++;

        }

        else {

            d[i] = vis[d[i]];

        }

    }

}



void fuzhi() {

    for(int i = 1;i <= m+1;i ++)    d[i] = c[i];

}



char s[22][22];



int main() {

    int i, j, k, l;

    while(scanf("%d%d", &n, &m) != -1) {

        for(i = 1;i <= n; i++)

            scanf("%s", s[i]+1);

        int tot = 0;

        for(i = 1;i <= n; i++)

            for(j = 1;j <= m; j++)

            if(s[i][j] == '.')  tot++;

        if(tot%2==1 || tot < 4) {

            puts("0");

            continue;

        }

        int tox  = -1, toy = -1;

        for(i = 1;i <= n; i++)

        for(j = 1;j <= m; j++) if(s[i][j] == '.') {

            tox = i;

            toy = j;

        }

        biao1.init();

        biao1.add(0, 1);

        LL ans = 0;

        for(i = 1;i <= n; i++){

            for(j = 0;j <= m; j++){

                biao2.init();

                for(l = 0;l < biao1.E; l++)  {

                    get(biao1.val[l]);

                    if(j == m) {

                        for(int ii = 2;ii <= m+1; ii++) d[ii] = c[ii-1];

                        d[1] = 0;

                        change();

                        LL now = getval();

                        biao2.add(now, biao1.cnt[l]);

                        continue;

                    }

                    if(c[j+1] && !c[j+2]) {  //  有左插头无上插头

                        if(s[i][j+1] != '.')  continue;

                        if(j+2 <= m) {

                            fuzhi();

                            d[j+1] = 0;d[j+2] = c[j+1];

                            change();

                            LL now = getval();

                            biao2.add(now, biao1.cnt[l]);

                        }

                        if(i < n) {

                            fuzhi();

                            change();

                            LL now = getval();

                            biao2.add(now, biao1.cnt[l]);

                        }

                    }

                    else if(!c[j+1] && c[j+2]) {  //  有上插头无左插头

                        if(s[i][j+1] != '.')  continue;

                        if(i < n) {

                            fuzhi();

                            d[j+1] = c[j+2]; d[j+2] = 0;

                            change();

                            LL now = getval();

                            biao2.add(now, biao1.cnt[l]);

                        }

                        if(j+2 <= m) {

                            fuzhi();

                            change();

                            LL now = getval();

                            biao2.add(now, biao1.cnt[l]);

                        }

                    }

                    else if(!c[j+1] && !c[j+2]) { //   左和上都无插头

                        if(s[i][j+1] != '.') {

                            fuzhi();

                            change();

                            LL now = getval();

                            biao2.add(now, biao1.cnt[l]);

                            continue;

                        }

                        if(j+2 <= m && i < n) {

                            fuzhi();

                            d[j+1] = d[j+2] = 13;

                            change();

                            LL now = getval();

                            biao2.add(now, biao1.cnt[l]);

                        }

                    }

                    else { //  左和上都有插头 ,  要判断左和上插头是否连通

                        if(c[j+2] == c[j+1]) {

                            int tot = 0;

                            for(int ii = 1;ii <= m+1; ii++) if(c[ii])

                                tot++;

                            if(tot == 2 && i == tox && j+1 == toy) ans += biao1.cnt[l];

                        }

                        else {

                            if(s[i][j+1] != '.')    continue;

                            fuzhi();

                            for(int ii = 1;ii <= m+1; ii++) if(ii != j+1 && ii != j+2 && d[ii] == d[j+1]) {

                                d[ii] = d[j+2];

                                break;

                            }

                            d[j+1] = d[j+2] = 0;

                            change();

                            LL now = getval();

                            biao2.add(now, biao1.cnt[l]);

                        }

                    }

                }

                biao1 = biao2;

            }

        }

        printf("%I64d\n", ans);

    }

    return 0;

}


 


 

你可能感兴趣的:(form)