插头DP专题

fzu 1977 格子分三种:不能走,可走可不走,一定要走。求单回路条数。

如果左上插头都为0 并且此格子可以不走 直接将状态加入到hash表中。记录最后一个必须走的格子 此后如果有回路形成 加入到结果。有回路形成 left=1 up=2 并且其它位置要全为0 为此WA了一晚上。。

另外 若plugDP最后return dp[0] 测试数据又无解 应写成
if(src->sz==0) return 0;
return src->dp[0]-2;

int M[15];
const int HSize = 12397;
int n , m , nn , mm ;
int maze[15][15];
int vis[15][15];

inline int CP(int p, int i) { return p & ( ~( 3 << M[i] ) ); }//第i位置零
inline int CP(int p, int i, int j) { return p & ( ~( 3 << M[i] ) ) & ( ~( 3 << M[j] ) ); }//i j位置零
inline int CP(int p, int i, int j, int k) { return p & ( ~( 3 << M[i] ) ) & ( ~( 3 << M[j] ) ) & ( ~( 3 << M[k] ) ); }//ijk置零
inline int getP(int p, int i) { return 3 & ( p >> M[i] ); }//取第i位
inline int setP(int i, int k) { return k << M[i]; }//第i位置为k
inline int getLP(int p, int j) {//找对应的左括号
    for ( int it = j - 1 , cnt = 1 ; ; it -- ) {
        int Pi = getP(p, it);
        if ( Pi == 1 ) cnt --;
        else if ( Pi == 2 ) cnt ++;
        if ( cnt == 0 ) return it;
    }
}
inline int getRP(int p, int j) {//找对应的右括号
    for ( int it = j + 1 , cnt = 1 ; ; it ++ ) {
        int Pi = getP(p, it);
        if ( Pi == 2 ) cnt --;
        else if ( Pi == 1 ) cnt ++;
        if ( cnt == 0 ) return it;
    }
}
struct HashMap {
    int Chart[HSize] ,  next[HSize] , sz;
    int MSK[HSize] ;
    long long dp[HSize] ;
    void clear() {
        sz = 0;
        memset(Chart, -1, sizeof( Chart ));
    }
    inline void push(int msk, long long val) {
        int x = msk % HSize;
        for ( int it = Chart[x] ; it != -1 ; it = next[it] ) {
            if ( MSK[it] == msk ) {
                dp[it]+=val;
                return;
            }
        }
        MSK[sz] = msk;
        dp[sz] = val;
        next[sz] = Chart[x];
        Chart[x] = sz ++;
    }
} HM[2] , *src , *des;

long long PlugDP() {
    src = HM;
    des = src + 1;
    src->clear();
    src->push(0, 1);
    long long ans=0;
    for ( int i = 0 ; i < n ; i ++ ) {
        for ( int k = 0 ; k < src->sz ; k ++ )
            src->MSK[k] <<= 2;
        for ( int j = 0 ; j < m ; j ++ ) {
            if ( !vis[i][j] ) continue;
            des->clear();
            for ( int k = 0 ; k < src->sz ; k ++ ) {
                int msk = src->MSK[k];
                long long val = src->dp[k] ;
                int left = getP(msk, j);
                int up = getP(msk, j + 1);
                if ( !left && !up ) {
                    if ( vis[i][j] == 1 ) des->push(msk , val);
                    if ( vis[i][j + 1] && vis[i + 1][j] ) des->push(msk | setP(j, 1) | setP(j + 1, 2), val);
                } else if ( !left || !up ) {
                    int w = left + up;
                    int temp = CP(msk, j, j + 1);
                    if ( vis[i + 1][j] ) des->push(temp | setP(j, w), val);
                    if ( vis[i][j + 1] ) des->push(temp | setP(j + 1, w), val);
                } else if ( left == up ) {
                    int it = ( left == 1 ) ? getRP(msk, j+1) : getLP(msk, j);
                    des->push(CP(msk, j, j + 1, it) | setP(it, left), val);
                } else if ( left == 2 && up == 1 ) des->push(CP(msk, j, j + 1), val);
                  else if ( (i > nn || (i==nn&&j>=mm)) && left == 1 && up == 2 ) //des->push(CP(msk, j, j + 1), val);
                    if(CP(msk,j,j+1)==0)
                        ans+=val;
            }
            swap(src, des);
        }
    }
    return //src->dp[0];
        ans;
}
int main() {
    for ( int i = 0 ; i < 15 ; i ++ )
        M[i] = ( i << 1 );
    int T;
    cin>>T;
    for ( int Case=1;Case<=T;Case++ ) {
        cin>>n>>m;
        string s="123456789012345";
        //memset(maze,0,sizeof(maze));
        for ( int i = 0 ; i < n ; i ++ ){
            cin>>s;
            for ( int j = 0 ; j < m ; j ++ ){
                if(s[j]=='*') maze[i][j]=1;
                else if(s[j]=='O') maze[i][j]=2;
                else maze[i][j]=0;
            }
        }
        if ( n < m ) {
            for ( int i = 0 ; i < n ; i ++ )
                for ( int j = i + 1 ; j < m ; j ++ )
                    swap(maze[i][j], maze[j][i]);
            swap(n, m);
        }
        nn=n-1; mm=m-1;
        memset(vis, false, sizeof( vis ));
        for ( int i = 0 ; i < n ; i ++ )
            for ( int j = 0 ; j < m ; j ++ ){
                if(maze[i][j]) vis[i][j] = maze[i][j] ;
                if(maze[i][j]==2) nn=i,mm=j;
            }
        printf("Case %d: %I64d\n",Case,PlugDP());
        //cout<<"Case "<<Case<<": "<<PlugDP()<<endl;
    }
    return 0;
}
View Code

 

hdu 1693 多回路

const int HSize = 199997;
int n , m;
int maze[13][13];
bool vis[13][13];

inline int CP(int p, int i) { return p & ( ~( 1 << i ) ); }//第i位置零
inline int CP(int p, int i, int j) { return p & ( ~( 1 << i ) ) & ( ~( 1 << j ) ); }//i j位置零
inline int CP(int p, int i, int j, int k) { return p & ( ~( 1 << i ) ) & ( ~( 1 << j ) ) & ( ~( 1 << k ) ); }//ijk置零
inline int getP(int p, int i) { return 1 & ( p >> i ); }//取第i位
inline int setP(int i, int k) { return k << i; }//第i位置为k

struct HashMap {
    int Chart[HSize] ,  next[HSize] , sz;
    int MSK[HSize] ;
    unsigned long long dp[HSize];
    void clear() {
        sz = 0;
        memset(Chart, -1, sizeof( Chart ));
    }
    inline void push(int msk, unsigned long long val) {
        int x = msk % HSize;
        for ( int it = Chart[x] ; it != -1 ; it = next[it] ) {
            if ( MSK[it] == msk ) {
                dp[it]+=val;
                return;
            }
        }
        MSK[sz] = msk;
        dp[sz] = val;
        next[sz] = Chart[x];
        Chart[x] = sz ++;
    }
} HM[2] , *src , *des;


long long PlugDP() {
    src = HM;
    des = src + 1;
    src->clear();
    src->push(0, 1);
    for ( int i = 0 ; i < n ; i ++ ) {
        for ( int k = 0 ; k < src->sz ; k ++ )
            src->MSK[k] <<= 1;
        for ( int j = 0 ; j < m ; j ++ ) {
            if ( !vis[i][j] ) continue;
            des->clear();
            for ( int k = 0 ; k < src->sz ; k ++ ) {
                int msk = src->MSK[k];
                unsigned long long val = src->dp[k] ;
                int left = getP(msk, j);
                int up = getP(msk, j + 1);
                if ( !left && !up ) {
                    if ( vis[i][j + 1] && vis[i + 1][j] ) des->push(msk | setP(j, 1) | setP(j + 1, 1), val);
                } else if ( !left || !up ) {
                    int w = left + up;
                    int temp = CP(msk, j, j + 1);
                    if ( vis[i + 1][j] ) des->push(temp | setP(j, w), val);
                    if ( vis[i][j + 1] ) des->push(temp | setP(j + 1, w), val);
                } else {
                    int temp = CP(msk, j, j + 1);
                    des->push(temp , val);
                }
            }
            swap(src, des);
        }
    }
    return src->dp[0];
}
int main() {
    int T;
    scanf("%d", &T);
    for(int t=1;t<=T;t++) {
        scanf("%d%d", &n, &m);//n行m列
        for ( int i = 0 ; i < n ; i ++ )
            for ( int j = 0 ; j < m ; j ++ )
                scanf("%d", &maze[i][j]);
        if ( n < m ) {
            for ( int i = 0 ; i < n ; i ++ )
                for ( int j = i + 1 ; j < m ; j ++ )
                    swap(maze[i][j], maze[j][i]);
            swap(n, m);
        }
        memset(vis, false, sizeof( vis ));
        for ( int i = 0 ; i < n ; i ++ )
            for ( int j = 0 ; j < m ; j ++ )
                if ( maze[i][j] ) vis[i][j] = true;
        cout<<"Case "<<t<<": There are "<<PlugDP()<<" ways to eat the trees."<<endl;
    }
    return 0;
}
View Code

 

poj 1739 单路径   从左下角走到右下角

分析:在最下面加一行 左边和右边两个格子为无障碍 其它为障碍 最后统计状态为100……002即可

int M[15];
const int HSize = 407;
int n , m;
bool vis[15][15];

inline int CP(int p, int i) { return p & ( ~( 3 << M[i] ) ); }//第i位置零
inline int CP(int p, int i, int j) { return p & ( ~( 3 << M[i] ) ) & ( ~( 3 << M[j] ) ); }//i j位置零
inline int CP(int p, int i, int j, int k) { return p & ( ~( 3 << M[i] ) ) & ( ~( 3 << M[j] ) ) & ( ~( 3 << M[k] ) ); }//ijk置零
inline int getP(int p, int i) { return 3 & ( p >> M[i] ); }//取第i位
inline int setP(int i, int k) { return k << M[i]; }//第i位置为k
inline int getLP(int p, int j) {//找对应的左括号
    for ( int it = j - 1 , cnt = 1 ; ; it -- ) {
        int Pi = getP(p, it);
        if ( Pi == 1 ) cnt --;
        else if ( Pi == 2 ) cnt ++;
        if ( cnt == 0 ) return it;
    }
}
inline int getRP(int p, int j) {//找对应的右括号
    for ( int it = j + 1 , cnt = 1 ; ; it ++ ) {
        int Pi = getP(p, it);
        if ( Pi == 2 ) cnt --;
        else if ( Pi == 1 ) cnt ++;
        if ( cnt == 0 ) return it;
    }
}

struct HashMap {
    int Chart[HSize] ,  next[HSize] , sz;
    int MSK[HSize] ;
    long long dp[HSize] ;
    void clear() {
        sz = 0;
        memset(Chart, -1, sizeof( Chart ));
    }
    inline void push(int msk, long long val) {
        int x = msk % HSize;
        for ( int it = Chart[x] ; it != -1 ; it = next[it] ) {
            if ( MSK[it] == msk ) {
                dp[it]+=val;
                return;
            }
        }
        MSK[sz] = msk;
        dp[sz] = val;
        next[sz] = Chart[x];
        Chart[x] = sz ++;
    }
} HM[2] , *src , *des;


long long PlugDP() {
    src = HM;
    des = src + 1;
    src->clear();
    src->push(0, 1);
    for ( int i = 0 ; i < n ; i ++ ) {
        for ( int k = 0 ; k < src->sz ; k ++ )
            src->MSK[k] <<= 2;
        for ( int j = 0 ; j < m ; j ++ ) {
            if ( !vis[i][j] ) continue;
            des->clear();
            for ( int k = 0 ; k < src->sz ; k ++ ) {
                int msk = src->MSK[k];
                long long val = src->dp[k] ;
                int left = getP(msk, j);
                int up = getP(msk, j + 1);
                if ( left==0 && up==0 ) {
                    if ( vis[i][j + 1] && vis[i + 1][j] ) des->push(msk | setP(j, 1) | setP(j + 1, 2), val);
                } else if ( left==0 || up==0 ) {
                    int w = left + up;
                    int temp = CP(msk, j, j + 1);
                    if ( vis[i + 1][j] ) des->push(temp | setP(j, w), val);
                    if ( vis[i][j + 1] ) des->push(temp | setP(j + 1, w), val);
                } else if ( left == up ) {
                    int it = ( left == 1 ) ? getRP(msk, j+1) : getLP(msk, j);
                    des->push(CP(msk, j, j + 1, it) | setP(it, left), val);
                } else if ( left == 2 && up == 1 ) des->push(CP(msk, j, j + 1), val);
            }
            swap(src, des);
        }
    }
    long long sta=(2<<(2*m-2))+1;
    for ( int k = 0 ; k < src->sz ; k ++ ) {
        if(src->MSK[k]==sta)
            return src->dp[k];
    }
    return 0;
}
int main() {
    for ( int i = 0 ; i < 15 ; i ++ )
        M[i] = ( i << 1 );
    /*while ( scanf("%d%d",&n,&m),n ) {
        memset(vis, false, sizeof( vis ));
        char ch;
        for ( int i = 0 ; i < n ; i ++ ){
            scanf("%c",&ch);
            for ( int j = 0 ; j < m ; j ++ ){
                scanf("%c", &ch);
                if( ch == '.'){
                    vis[i][j]=1;
                }
            }
        }*/
    while ( cin>>n>>m,n ) {
        memset(vis, false, sizeof( vis ));
        char ch;
        for ( int i = 0 ; i < n ; i ++ ){
            for ( int j = 0 ; j < m ; j ++ ){
                cin>>ch;
                if( ch == '.'){
                    vis[i][j]=1;
                }
            }
        }
        vis[n][0]=vis[n][m-1]=1;
        //printf("%I64d\n", PlugDP());
        cout<<PlugDP()<<endl;
    }
    return 0;
}
View Code

 

poj 3133   有两个格子为2 两个格子为3  要求2到2连起来  3到3连起来  并使连线最短

插头设置为0是没插头,1是连接关键点2的线,2是连接关键点3的线。
对于0的格子:00 -> 00,11,22;01/10 -> 01/10;02/20 -> 02/20;11/22 -> 00。
对于1的格子:00 -> 00。
对于2的格子:01/10 -> 00,00 -> 01/10。
对于3的格子:02/20 -> 00,00 -> 02/20。

int M[15];
const int HSize = 11137;
int n , m ;
int maze[15][15];
int vis[15][15];

inline int CP(int p, int i) { return p & ( ~( 3 << M[i] ) ); }//第i位置零
inline int CP(int p, int i, int j) { return p & ( ~( 3 << M[i] ) ) & ( ~( 3 << M[j] ) ); }//i j位置零
inline int CP(int p, int i, int j, int k) { return p & ( ~( 3 << M[i] ) ) & ( ~( 3 << M[j] ) ) & ( ~( 3 << M[k] ) ); }//ijk置零
inline int getP(int p, int i) { return 3 & ( p >> M[i] ); }//取第i位
inline int setP(int i, int k) { return k << M[i]; }//第i位置为k
inline int getLP(int p, int j) {//找对应的左括号
    for ( int it = j - 1 , cnt = 1 ; ; it -- ) {
        int Pi = getP(p, it);
        if ( Pi == 1 ) cnt --;
        else if ( Pi == 2 ) cnt ++;
        if ( cnt == 0 ) return it;
    }
}
inline int getRP(int p, int j) {//找对应的右括号
    for ( int it = j + 1 , cnt = 1 ; ; it ++ ) {
        int Pi = getP(p, it);
        if ( Pi == 2 ) cnt --;
        else if ( Pi == 1 ) cnt ++;
        if ( cnt == 0 ) return it;
    }
}

struct HashMap {
    int Chart[HSize] ,  next[HSize] , sz;
    int MSK[HSize] ;
    long long dp[HSize] ;
    void clear() {
        sz = 0;
        memset(Chart, -1, sizeof( Chart ));
    }
    inline void push(int msk, long long val) {
        int x = msk % HSize;
        for ( int it = Chart[x] ; it != -1 ; it = next[it] ) {
            if ( MSK[it] == msk ) {
                dp[it] = dp[it] < val ? dp[it] : val;
                return;
            }
        }
        MSK[sz] = msk;
        dp[sz] = val;
        next[sz] = Chart[x];
        Chart[x] = sz ++;
    }
} HM[2] , *src , *des;


long long PlugDP() {
    src = HM;
    des = src + 1;
    src->clear();
    src->push(0, 0);
    //long long ans=0;
    for ( int i = 0 ; i < n ; i ++ ) {
        for ( int k = 0 ; k < src->sz ; k ++ )
            src->MSK[k] <<= 2;
        for ( int j = 0 ; j < m ; j ++ ) {
            if ( !vis[i][j] ) continue;
            des->clear();
            if(vis[i][j]==2)
                for ( int k = 0 ; k < src->sz ; k ++ ) {
                    int msk = src->MSK[k];
                    long long val = src->dp[k] + 1;
                    int left = getP(msk, j);
                    int up = getP(msk, j + 1);
                    if(up+left==1) des->push(CP(msk,j,j+1),val);
                    else if(!left&&!up){
                        int temp=CP(msk,j,j+1);
                        if(vis[i+1][j])des->push(temp|setP(j,1),val);
                        if(vis[i][j+1])des->push(temp|setP(j+1,1),val);
                    }
                }
            else if(vis[i][j]==3)
                for ( int k = 0 ; k < src->sz ; k ++ ) {
                    int msk = src->MSK[k];
                    long long val = src->dp[k] + 1;
                    int left = getP(msk, j);
                    int up = getP(msk, j + 1);
                    if((left==2&&up==0)||(left==0&&up==2)) des->push(CP(msk,j,j+1),val);
                    else if(!left&&!up){
                        int temp=CP(msk,j,j+1);
                        if(vis[i+1][j])des->push(temp|setP(j,2),val);
                        if(vis[i][j+1])des->push(temp|setP(j+1,2),val);
                    }
                }
            else
            for ( int k = 0 ; k < src->sz ; k ++ ) {
                int msk = src->MSK[k];
                long long val = src->dp[k] + 1;
                int left = getP(msk, j);
                int up = getP(msk, j + 1);
                if ( !left && !up ) {
                    des->push(msk , val - 1);
                    if ( vis[i][j + 1] && vis[i + 1][j] ) {
                        des->push(msk | setP(j, 1) | setP(j + 1, 1), val);
                        des->push(msk | setP(j, 2) | setP(j + 1, 2), val);
                    }
                } else if ( !left || !up ) {
                    int w = left + up;
                    int temp = CP(msk, j, j + 1);
                    if ( vis[i + 1][j] ) des->push(temp | setP(j, w), val);
                    if ( vis[i][j + 1] ) des->push(temp | setP(j + 1, w), val);
                } else if ( left == up ) {
                    des->push(CP(msk, j, j + 1), val);
                }
            }
            swap(src, des);
        }
    }
    if(src->sz==0) return 0;        //无解
    return src->dp[0]-2;
        //ans;
}
int main() {
    for ( int i = 0 ; i < 15 ; i ++ )
        M[i] = ( i << 1 );
    while ( cin>>n>>m && n ) {
        for ( int i = 0 ; i < n ; i ++ )
            for ( int j = 0 ; j < m ; j ++ )
                cin>>maze[i][j];
        if ( n < m ) {
            for ( int i = 0 ; i < n ; i ++ )
                for ( int j = i + 1 ; j < m ; j ++ )
                    swap(maze[i][j], maze[j][i]);
            swap(n, m);
        }
        memset(vis, 0, sizeof( vis ));
        for ( int i = 0 ; i < n ; i ++ )
            for ( int j = 0 ; j < m ; j ++ )
                if ( maze[i][j] == 0 ) vis[i][j] = 1;
                else if( maze[i][j] == 2) vis[i][j]=2;
                else if( maze[i][j] == 3) vis[i][j]=3;
        printf("%I64d\n",PlugDP());
        //cout<<PlugDP()<<endl;
    }
    return 0;
}
View Code

 

Timus 1519 多回路

int Pos[15],cp[15],sp[4][15];
const int HSize = 32117;
int n , m , nn , mm ;
int maze[15][15];
int vis[15][15];

// state & cp[i] 将第i位置为0
// state & cp[i] | sp[k][i] 将第i位置为k
void init(){
    for ( int i = 0 ; i < 15 ; i ++ ){
        Pos[i] = ( i << 1 );
        cp[i] = ~( 3 << Pos[i]);
    }
    for ( int i = 0 ; i < 4 ; i ++ )
        for ( int j = 0 ; j < 15 ; j ++ )
            sp[i][j] = i << Pos[j];
}

void readData(){
    char ch;
    for ( int i = 0 ; i < n ; i ++ ){
        for ( int j = 0 ; j < m ; j ++ ){
            cin>>ch;
            maze[i][j]=ch=='.';
        }
    }
    if ( n < m ) {
        for ( int i = 0 ; i < n ; i ++ )
            for ( int j = i + 1 ; j < m ; j ++ )
                swap(maze[i][j], maze[j][i]);
        swap(n, m);
    }
    memset(vis, 0, sizeof( vis ));
    for ( int i = 0 ; i < n ; i ++ )
        for ( int j = 0 ; j < m ; j ++ )
            if ( maze[i][j] ) vis[i][j] = 1,nn=i,mm=j;
}

inline int getP(int p, int i) { return 3 & ( p >> Pos[i] ); }//取第i位
inline int getLP(int p, int j) {//找对应的左括号
    for ( int it = j - 1 , cnt = 1 ; ; it -- ) {
        int Pi = getP(p, it);
        if ( Pi == 1 ) cnt --;
        else if ( Pi == 2 ) cnt ++;
        if ( cnt == 0 ) return it;
    }
}
inline int getRP(int p, int j) {//找对应的右括号
    for ( int it = j + 1 , cnt = 1 ; ; it ++ ) {
        int Pi = getP(p, it);
        if ( Pi == 2 ) cnt --;
        else if ( Pi == 1 ) cnt ++;
        if ( cnt == 0 ) return it;
    }
}

struct HashMap {
    int Chart[HSize] ,  pre[HSize] , sz;
    int State[HSize] ;
    long long dp[HSize] ;
    void clear() {
        sz = 0;
        memset(Chart, -1, sizeof( Chart ));
    }
    inline void push(int sta, long long val) {
        int x = sta % HSize;
        for ( int it = Chart[x] ; it != -1 ; it = pre[it] ) {
            if ( State[it] == sta ) {
                dp[it]+=val;
                return;
            }
        }
        State[sz] = sta;
        dp[sz] = val;
        pre[sz] = Chart[x];
        Chart[x] = sz ++;
    }
} HM[2] , *src , *des;


long long PlugDP() {
    src = HM;
    des = src + 1;
    src->clear();
    src->push(0, 1);
    long long ans=0;
    for ( int i = 0 ; i < n ; i ++ ) {
        for ( int k = 0 ; k < src->sz ; k ++ )
            src->State[k] <<= 2;
        for ( int j = 0 ; j < m ; j ++ ) {
            if ( !vis[i][j] ) continue;
            des->clear();
            for ( int k = 0 ; k < src->sz ; k ++ ) {
                int sta = src->State[k];
                long long val = src->dp[k] ;
                int left = getP(sta, j);
                int up = getP(sta, j + 1);
                if ( !left && !up ) {
                    if ( vis[i][j + 1] && vis[i + 1][j] ) des->push(sta | sp[1][j] | sp[2][j+1], val);
                } else if ( !left || !up ) {
                    int w = left + up;
                    int temp = sta & cp[j] & cp[j+1];
                    if ( vis[i + 1][j] ) des->push(temp | sp[w][j], val);
                    if ( vis[i][j + 1] ) des->push(temp | sp[w][j+1], val);
                } else if ( left == up ) {
                    int it = ( left == 1 ) ? getRP(sta, j+1) : getLP(sta, j);
                    des->push(sta & cp[j] & cp[j+1] & cp[it] | sp[left][it], val);
                } else if ( left == 2 && up == 1 ) des->push(sta & cp[j] & cp[j+1], val);
                  else if ( i == nn && j == mm && left == 1 && up == 2 ) //des->push(CP(sta, j, j + 1), val);
                        ans+=val;
            }
            swap(src, des);
        }
    }
    return //src->dp[0];
        ans;
}

int main() {
    init();
    while (cin>>n>>m) {
        readData();
        printf("%I64d\n",PlugDP());
    }
    return 0;
}
View Code

 

zju 3213 花园被分成m*m的方块 有的方块是障碍,每个方块有权值 障碍的权值为0,非障碍方块只能走一次 问怎么走经过的权值最大

简单路径 不过不是求路线条数 而是求权值 不一定要走完所有非障碍方块

int M[10];
const int HSize = 30007;
int n , m;
int maze[7][7];
bool vis[8][8];

inline int CP(int p, int i) { return p & ( ~( 3 << M[i] ) ); }//第i位置零
inline int CP(int p, int i, int j) { return p & ( ~( 3 << M[i] ) ) & ( ~( 3 << M[j] ) ); }//i j位置零
inline int CP(int p, int i, int j, int k) { return p & ( ~( 3 << M[i] ) ) & ( ~( 3 << M[j] ) ) & ( ~( 3 << M[k] ) ); }//ijk置零
inline int getP(int p, int i) { return 3 & ( p >> M[i] ); }//取第i位
inline int setP(int i, int k) { return k << M[i]; }//第i位置为k
inline int cntSP(int p, int cnt = 0) {//独立插头数量
    for ( ; p ; p >>= 2 )
        cnt += ( ( p & 3 ) == 3 );
    return cnt;
}
inline int getLP(int p, int j) {//找对应的左括号
    for ( int it = j - 1 , cnt = 1 ; ; it -- ) {
        int Pi = getP(p, it);
        if ( Pi == 1 ) cnt --;
        else if ( Pi == 2 ) cnt ++;
        if ( cnt == 0 ) return it;
    }
}
inline int getRP(int p, int j) {//找对应的右括号
    for ( int it = j + 1 , cnt = 1 ; ; it ++ ) {
        int Pi = getP(p, it);
        if ( Pi == 2 ) cnt --;
        else if ( Pi == 1 ) cnt ++;
        if ( cnt == 0 ) return it;
    }
}

inline void checkmax(int &a, const int &b) { if ( a < b ) a = b; }
struct HashMap {
    int Chart[HSize] , dp[HSize] , MSK[HSize] , next[HSize] , sz;
    void clear() {
        sz = 0;
        memset(Chart, -1, sizeof( Chart ));
    }
    inline void push(int msk, int val) {
        int x = msk % HSize;
        for ( int it = Chart[x] ; it != -1 ; it = next[it] ) {
            if ( MSK[it] == msk ) {
                checkmax(dp[it], val);
                return;
            }
        }
        MSK[sz] = msk;
        dp[sz] = val;
        next[sz] = Chart[x];
        Chart[x] = sz ++;
    }
} HM[2] , *src , *des;


int PlugDP() {
    src = HM;
    des = src + 1;
    src->clear();
    src->push(0, 0);
    int ret = 0;
    for ( int i = 0 ; i < n ; i ++ ) {
        for ( int k = 0 ; k < src->sz ; k ++ )
            src->MSK[k] <<= 2;
        for ( int j = 0 ; j < m ; j ++ ) {
            if ( !vis[i][j] ) continue;
            checkmax(ret, maze[i][j]);
            des->clear();
            for ( int k = 0 ; k < src->sz ; k ++ ) {
                int msk = src->MSK[k];
                int val = src->dp[k] + maze[i][j];
                int left = getP(msk, j);
                int up = getP(msk, j + 1);
                if ( !left && !up ) {
                    des->push(msk, src->dp[k]);//能走但不走
                    if ( vis[i][j + 1] && vis[i + 1][j] ) des->push(msk | setP(j, 1) | setP(j + 1, 2), val);
                    if ( cntSP(msk) > 1 ) continue;
                    if ( vis[i + 1][j] ) des->push(msk | setP(j, 3), val);
                    if ( vis[i][j + 1] ) des->push(msk | setP(j + 1, 3), val);
                } else if ( !left || !up ) {
                    int w = left + up;
                    int temp = CP(msk, j, j + 1);
                    if ( vis[i + 1][j] ) des->push(temp | setP(j, w), val);
                    if ( vis[i][j + 1] ) des->push(temp | setP(j + 1, w), val);
                    if ( w != 3 && cntSP(msk) <= 1 ) {
                        int it = ( w == 1 ) ? getRP(msk, j+1) : getLP(msk, j);

                        des->push(CP(temp, it) | setP(it, 3), val);
                    } else if ( w == 3 && temp == 0 ) checkmax(ret, val);
                } else if ( left == up ) {
                    if ( left < 3 ) {
                        int it = ( left == 1 ) ? getRP(msk, j+1) : getLP(msk, j);
                        des->push(CP(msk, j, j + 1, it) | setP(it, left), val);
                    } else if ( CP(msk, j, j + 1) == 0 ) checkmax(ret, val);
                } else if ( left == 3 || up == 3 ) {
                    int it = ( left + up - 3 == 1 ) ? getRP(msk, j+1) : getLP(msk, j);
                    des->push(CP(msk, j, j + 1, it) | setP(it, 3), val);
                } else if ( left == 2 && up == 1 ) des->push(CP(msk, j, j + 1), val);
            }
            swap(src, des);
        }
    }
    return ret;
}
int main() {
    for ( int i = 0 ; i < 10 ; i ++ )
        M[i] = ( i << 1 );
    int T;
    scanf("%d", &T);
    while ( T -- ) {
        scanf("%d%d", &n, &m);
        for ( int i = 0 ; i < n ; i ++ )
            for ( int j = 0 ; j < m ; j ++ )
                scanf("%d", &maze[i][j]);
        if ( n < m ) {
            for ( int i = 0 ; i < n ; i ++ )
                for ( int j = i + 1 ; j < m ; j ++ )
                    swap(maze[i][j], maze[j][i]);
            swap(n, m);
        }
        memset(vis, false, sizeof( vis ));
        for ( int i = 0 ; i < n ; i ++ )
            for ( int j = 0 ; j < m ; j ++ )
                if ( maze[i][j] ) vis[i][j] = true;
        printf("%d\n", PlugDP());
    }
    return 0;
}
View Code

 

posted @ 2013-06-19 13:48  心向往之  阅读(274)  评论(0编辑  收藏  举报