• HDU 4949 Light(插头dp、位运算)


    比赛的时候没看题,赛后看题觉得比赛看到应该可以敲的,敲了之后发现还真就会卡题。。

    因为写完之后,无限TLE。。。

    直到后来用位运算代替了我插头dp常用的decode、encode、shift三个函数以及改改HASH值才勉强过的。。。7703ms

    题意:给一个N*M的01矩阵,每次可以选一个格子进行2种操作,①翻转邻居格子②翻转邻居格子和自己。输出最小的总操作数使得矩阵全为0.

    显然每个格子有4种操作(一、不操作;二、①②;三、①;四、②)。

    一开始写的时候用2位表示一个插头,一位用于表示翻转当前格子,一位表示插头的源头需要被翻转。然后空间就是2*3*(4^10)感觉有点不科学

    后来发现,其实,我们可以这样归类,①不操作(花费0);②翻自己(花费2);③翻转邻居(花费1);这样空间就是2*3*(3^10)

    其中③包括2种情况,事实上,如果对一个格子A进行了第③种操作,那这个格子的邻居格子BCDE做任何操作,A都可以熄灯

    还有就是,答案一定小于等于一开始矩阵的1的个数的2倍,可以用这个进行一定程度的剪枝。

    然后就是各种位运算了。。。。搞得我都晕了。。。

    另外,其实,因为这样插头dp需要消耗很多额外的花费(清空hash表什么的),所以速度应该是比直接dp[i][j][k]要慢一些的(主要应该是m小的时候k<tot清空比清空hash表快)。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    
    
    #define HASH 100007
    #define STATE 500010
    #define maxd 15
    
    int maze[maxd][maxd];
    int code[maxd];
    int n,m;
    struct HASHMAP{
        int head[HASH];
        int state[STATE],nxt[STATE];
        int f[STATE];
        int sz;
        void clear(){sz=0;memset(head,-1,sizeof(head));}
        void push(int st,int ans){
            int h=st%HASH;
            for(int i=head[h];i!=-1;i=nxt[i]){
                if(st==state[i]){
                    f[i] = f[i]<ans?f[i]:ans;
                    return ;
                }
            }
            state[sz]=st,nxt[sz]=head[h],f[sz]=ans;
            head[h]=sz++;
        }
    }hm[2];
    void decode(int st){
        for(int i=m;i>=0;--i) code[i]=st&3,st>>=2;
    }
    int encode(){
        int ret=0;
        for(int i=0;i<=m;++i) ret=ret<<2|code[i];
        return ret;
    }
    void shift(){
        for(int i=m;i;--i) code[i]=code[i-1];
        code[0]=0;
    }
    int ans;
    int zo,oz,oo;
    void dpblank(int i,int j,int cur){
        int mv = j==m?2:0;
        int all = (1<<(2*(m+1)-mv) ) -1;
        for(int k=0;k<hm[cur].sz;++k){
            int st = hm[cur].state[k];
            int left = st&(oo>>(2*(j-1))), up = st&(oo>>(2*j));
            int L = left>>(2*(m-j+1)), U = up>>(2*(m-j));
            int cnt = ((L>>1)+(U>>1))&1;
            if(i==1 || U==2 || maze[i-1][j]==U){
                int st2 = st^left^up;
                if(cnt) st2 = st2 | (zo>>(2*(j-1))) | (zo>>(2*j));
                hm[cur^1].push((st2>>mv)&all, hm[cur].f[k]);
            }
            if(hm[cur].f[k]+2<ans)
            if(i==1 || U==2 || maze[i-1][j]==U){
                int st2 = st^left^up;
                if(!cnt) st2 = st2 | (zo>>(2*(j-1))) | (zo>>(2*j));
                hm[cur^1].push((st2>>mv)&all, hm[cur].f[k]+2);
            }
            if(hm[cur].f[k]+1<ans)
            if(i==1 || U==2 || maze[i-1][j]!=U){
                int st2 = st^left^up;
                if(j>1 && L!=2) st2 = st2 ^ (zo>>(2*(j-2)));
                st2 = st2 | (oz>>(2*(j-1))) | (oz>>(2*j));
                hm[cur^1].push((st2>>mv)&all, hm[cur].f[k]+1);
            }
        }
    }
    void solve(){
        zo = 1<<(2*m);
        oz = 2<<(2*m);
        oo = 3<<(2*m);
        int cur=0;
        hm[0].clear();
        hm[0].push(0,0);
        for(int i=1;i<=n;++i){
            for(int j=1;j<=m;++j){
                hm[cur^1].clear();
                dpblank(i,j,cur);
                cur^=1;
            }
        }
        for(int k=0;k<hm[cur].sz;++k){
            bool yes=true;
            decode(hm[cur].state[k]);
            for(int j=1;j<=m;++j){
                if(code[j]!=2 && code[j]!=maze[n][j]){
                    yes=false;
                    break;
                }
            }
            if(yes) ans = ans<hm[cur].f[k]?ans:hm[cur].f[k];
        }
    }
    int main(){
        int ca=0;
        while(~scanf("%d%d",&n,&m) && n){
            printf("Case #%d: ",++ca);
            ans=0;
            for(int i=1;i<=n;++i) for(int j=1;j<=m;++j)
                scanf("%1d",maze[i]+j), ans+=maze[i][j];
            ans*=2;
            solve();
            printf("%d
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    简答题补充
    问答题相关
    如何在Android 4.0 ICS中禁用StatusBar | SystemBar | 状态栏
    《Win32Asm与Radasm开发教程》第四部精彩实例分析!!20120228更新完毕!!
    排序
    SpringCloud微服务框架搭建
    Spring Cloud报错No instances available for XXX解决办法
    mybatis复杂查询(一对多,多对一)
    Linux:在文件中查找指定内容并输出到文件
    flask异常处理 abort errorhandler
  • 原文地址:https://www.cnblogs.com/nextbin/p/3915042.html
Copyright © 2020-2023  润新知