HDU 1693 Eat the Trees

来源:互联网 发布:淘宝swatch官方旗舰店 编辑:程序博客网 时间:2024/05/19 10:12

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1693


题意:给一个n*m的地图,1可走,0不可走。现在可以在地图上构建若干条回路,使得覆盖所有的1,不覆盖任何一个0,而且每个1只能被覆盖一次,求不同的方案。


思路:比较简单的插头dp,0的格子无连通,1的格子一定有两个连通(在回路中)。分类转移即可。


#include <cstdio>#include <cmath>#include <cstring>#include <string>#include <cstdlib>#include <iostream>#include <algorithm>using namespace std;#define rep(i,j,k) for (int i=j;i<=k;i++)#define Rrep(i,j,k) for (int i=j;i>=k;i--)#define Clean(x,y) memset(x,y,sizeof(x))#define LL long longconst int maxn = 4111;int n , m;int cur , pre;int g[20][20];struct hashtable{    int head[maxn] , next[maxn] , state[maxn] , size;    LL  value[maxn];    void clear()    {        Clean(head,-1);        size = 0;    }    void push( int S , LL V )    {        int h = S % maxn;        for( int k = head[h]; k != -1; k = next[k] )            if ( state[k] == S )            {                value[k] += V;                return;            }        state[size] = S , value[size] = V;        next[size] = head[h] , head[h] = size++;    }}dp[2];void DP( int x , int y , int k ){    int S = dp[pre].state[k];    LL V = dp[pre].value[k];    int left = S & (1<<(y-1))  , up = S & (1<<y);    S = S ^ left ^ up; //去掉左边和上边的状态    //S状态转移到下一格时,只有第y位和y-1位可能改变,所以先把y和y-1位变为0,根据需求再添加    if ( !g[x][y] )    {        if ( !left && !up ) dp[cur].push( S , V ); //右 下无连通,y 和 y-1位为0    }    else    {        if ( !left && !up ) //无连通 , 右下必须要都连通        {            //如果右下可以满足连通条件            if ( x < n && y < m && g[x+1][y] && g[x][y+1] ) dp[cur].push( S^(1<<y)^( 1<<(y-1) ) , V );        }        else if ( !left || !up ) //单连通 , 分别尝试右和下连通        {            if ( x < n && g[x+1][y] ) dp[cur].push( S^( 1<<(y-1) ) , V );            if ( y < m && g[x][y+1] ) dp[cur].push( S^(1<<y) , V );        }        else dp[cur].push( S , V ); //双联通 , 右下无连通    }}void solve(){    cur = 0 , dp[cur].clear();    dp[0].push( 0 , 1 );    rep(i,1,n)    {        pre = cur , cur ^= 1;        dp[cur].clear();        for( int k = 0; k < dp[pre].size; k++ ) dp[cur].push( dp[pre].state[k]<<1 , dp[pre].value[k] );        rep(j,1,m)        {            pre = cur , cur^=1 , dp[cur].clear();            for( int k = 0; k < dp[pre].size; k++ )            DP( i , j , k );        }    }    LL ans = 0;    for( int k = 0; k < dp[cur].size; k++ )        if ( dp[cur].state[k] == 0 ) {ans = dp[cur].value[k];break;}    printf("There are %lld ways to eat the trees.\n",ans);}int main(){    int T;    cin>>T;    rep(cas,1,T)    {        scanf("%d%d",&n,&m);        rep(i,1,n) rep(j,1,m) scanf("%d",&g[i][j]);        printf("Case %d: ",cas);        solve();    }    return 0;}




0 0