1. 程式人生 > >hdu1693 Eat the Trees 插頭dp

hdu1693 Eat the Trees 插頭dp

i++ vector HERE con rst tun fin 輪廓線 link

題意:有障礙物的多回路的插頭dp,求方案數
題解:其實搞懂插頭dp的插頭方式就和輪廓線dp一樣了,因為這題是多回路,不需要單回路的連通性;‘
dp[i][j]表示第i行j狀態的方案數
需要註意的是第二維我們維護了m+1個狀態,因為對於插頭可能會有m+1種情況,對於每一個位置有插頭就是1,否則就是0
一共有四種情況:
假設當前位置是障礙物,那麽只有沒有上插頭和左插頭的情況能夠轉移到沒有上左插頭的情況
假設當前位置不是障礙物,那麽

  1. 有上插頭和左插頭,直接合並兩個插頭
  2. 有上插頭沒有左插頭,如果能向下,延伸上插頭。如果能向右,上插頭變成左插頭
  3. 沒有上插頭有左插頭,如果能向右,延伸左插頭。如果能向下,左插頭變成上插頭
  4. 沒有上左插頭,如果能向右和向下,增加一個左插頭和上插頭
    最後沒有上插頭和左插頭的方案數就是答案
//#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast,no-stack-protector")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
//#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pi acos(-1.0)
#define ll long long
#define vi vector<int>
#define mod 1000000007
#define C 0.5772156649
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define pil pair<int,ll>
#define pli pair<ll,int>
#define pii pair<int,int>
#define cd complex<double>
#define ull unsigned long long
#define base 1000000000000000000
#define fio ios::sync_with_stdio(false);cin.tie(0)

using namespace std;

const double g=10.0,eps=1e-12;
const int N=(1ll<<12)+10,maxn=1000+10,inf=0x3f3f3f3f,INF=0x3f3f3f3f3f3f3f3f;

ll dp[2][N];
int n,m,a[12][12];
ll solve()
{
    memset(dp,0,sizeof dp);
    int now=0,pre=1;
    dp[now][0]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            swap(now,pre);
            memset(dp[now],0,sizeof dp[now]);
            if(a[i][j]==0)
            {
                for(int k=0;k<(1<<(m+1));k++)
                    if((!((k>>m)&1)) && (!(k&1)))
                        dp[now][k<<1]+=dp[pre][k];
                continue;
            }
            for(int k=0;k<(1<<(m+1));k++)
            {
                if(((k>>m)&1) && (!(k&1)))
                {
                    if(j!=m)dp[now][((k^(1<<m))<<1)|1]+=dp[pre][k];
                    if(i!=n)dp[now][((k^(1<<m))<<1)|2]+=dp[pre][k];
                }
                else if((!((k>>m)&1)) && (k&1))
                {
                    if(i!=n)dp[now][k<<1]+=dp[pre][k];
                    if(j!=m)dp[now][(k<<1)^3]+=dp[pre][k];
                }
                else if((!((k>>m)&1)) && (!(k&1)))
                {
                    if(j!=m&&i!=n)dp[now][(k<<1)|3]+=dp[pre][k];
                }
                else
                {
                    dp[now][((k^(1<<m))<<1)^2]+=dp[pre][k];
                }
            }
        }
    }
    return dp[now][0];
}
int main()
{
    int T;scanf("%d",&T);
    for(int _=1;_<=T;_++)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                scanf("%d",&a[i][j]);
        printf("Case %d: There are %lld ways to eat the trees.\n",_,solve());
    }
    return 0;
}
/***********************

***********************/

hdu1693 Eat the Trees 插頭dp