zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    poj 2488 DFS
    畅通工程 并查集模版
    KMP 模板
    poj 1426 DFS
    poj 2528 线段数
    poj 3468 线段数 修改区间(点)
    CVPR2012文章阅读(2)A Unified Approach to Salient Object Detection via Low Rank Matrix Recovery
    如何制定目标
    Saliency Map 最新综述
    计算机视觉模式识别重要会议杂志
  • 原文地址:https://www.cnblogs.com/nextbin/p/3915042.html
Copyright © 2011-2022 走看看