1. 程式人生 > >FZU - 1977 Pandora adventure【插頭DP】

FZU - 1977 Pandora adventure【插頭DP】

Pandora adventure
Time Limit: 1000MS
Memory Limit: 32768KB
64bit IO Format: %I64d & %I64u

 Status

Description

The pollution of the earth is so serious that people can not survive any more. Fortunately, people have found a new planet that maybe has life, and we call it "Pandora Planet".

Leonardo Da Vinci is the only astronaut on the earth. He will be sent to the Pandora Planet to gather some plant specimens and go back. The plant specimen is important to the people to decide whether the planet is fit to live or not.

Assuming that Da Vinci can only move in an N×M grid. The positions of the plant specimens he wants to collect are all marked by the satellite. His task is to find a path to collect all the plant specimens and return to the spaceship. There are some savage beasts in the planet. Da Vinci can not investigate the grid with the savage beast. These grids are also marked by the satellite. In order to save time Da Vinci could only visit each grid exactly once and also return to the start grid, that is, you can not visit a grid twice except the start grid. You should note that you can choose any grid as the start grid.

Now he wants to know the number of different paths he can collect all the plant specimens. We only care about the path and ignore where the start grid is, so the two paths in Figure 1 are considered as the same.

Figure 1

Input

The first line of the input contains an integer T (T≤100), indicating the number of cases. Each case begins with a line containing two integers N and M (1≤N, M≤12), the size of the planet is N×M. Each of the following N lines contains M characters Gij(1≤i≤N, 1≤j≤M), Gij

 denotes the status of the grid in row i and column j, where 'X' denotes the grid with savage beast, '*' denotes the safe grid that you can decide to go or not, 'O' denotes the plant specimen you should collect. We guarantee that there are at least three plant specimens in the map.

Output

For each test case, print a line containing the test case number (beginning with 1) and the number of different paths he can collect all the plant specimens. You can make sure that the answer will fit in a 64-bit signed integer.

Sample Input

2
2 2
OO
O*
4 4
***O
XO**
**O*
XX**

Sample Output

Case 1: 1
Case 2: 7


題意:

給出一個n*m圖,圖中‘O’代表的格子必須經過,‘X’的格子不能經過,‘*’的格子可經過也可不經過,所有格子最多隻能經過一次,求有多少條迴路滿足條件?

解題思路:

這題就是在Formula 1的基礎上稍做改動,唯一不同的是‘*’代表的點可以有插頭,也可以沒插頭,增加一種情況繼續dp就可以了。

程式碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<map>
#include<string>
#include<queue>
#include<vector>
#include<list>
#include<bitset>
//#pragma comment(linker,"/STACK:1024000000,1024000000")
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
const int HASH=30007;
const int STATE=500010;
struct HASHMAP
{
    int head[HASH],next[STATE],size;
    ll state[STATE];
    ll f[STATE];
    void init()
    {
        size=0;
        memset(head,-1,sizeof(head));
    }
    void push(long long st,long long ans)
    {
        int i;
        int h=st%HASH;
        for(i=head[h];i!=-1;i=next[i])//這裡要注意是next
          if(state[i]==st)
          {
              f[i]+=ans;
              return;
          }
        state[size]=st;
        f[size]=ans;
        next[size]=head[h];
        head[h]=size++;
    }
}hm[2];
char Mp[20][20];
int n,m;
int ex,ey;
ll ans;
void encode(ll &code,int a[])
{
    code=0;
    for(int i=m; i>=0; i--)
    {
        code<<=2;
        code|=(ll)a[i];
    }
}
void uncode(ll code,int a[])
{
    for(int i=0; i<=m; i++)
    {
        a[i]=code&3;
        code>>=2;
    }
}
void add(int a[],int c)
{
    a[c]=1;
    a[c+1]=2;
}
void Merge(int a[],int c)
{
    int num=0;
    if(a[c]==1&&a[c+1]==1)
    {
        for(int i=c+1;i<=m;i++)
        {
            if(a[i]==1) num++;
            else if(a[i]==2) num--;
            if(num==0&&a[i]==2)
            {
                a[i]=1;break;
            }
        }
    }
    else if(a[c]==2&&a[c+1]==2)
    {
        for(int i=c;i>=0;i--)
        {
            if(a[i]==2) num++;
            else if(a[i]==1) num--;
            if(num==0&&a[i]==1)
            {
                a[i]=2;break;
            }
        }
    }
    a[c]=a[c+1]=0;
}
void show(int a[])
{
    for(int i=0;i<=m;i++) printf("%d%c",a[i],i==m?'\n':' ');
}
void dpplant(int x,int y,int cur)
{
    int a[20];
    ll code;
    HASHMAP &now=hm[cur];
    HASHMAP &to=hm[cur^1];
    for(int i=0;i<now.size;i++)
    {
        uncode(now.state[i],a);
        if(!a[y]&&!a[y+1])
        {
            if(x==n-1||y==m-1||Mp[x+1][y]=='X'||Mp[x][y+1]=='X') continue;
            a[y]=1,a[y+1]=2;
            encode(code,a);
            if(y==m-1) code<<=2;
            to.push(code,now.f[i]);
        }
        else if(!a[y]&&a[y+1]||a[y]&&!a[y+1])
        {
            int val=max(a[y],a[y+1]);
            if(x!=n-1&&Mp[x+1][y]!='X')
            {
                a[y]=val,a[y+1]=0;
                encode(code,a);
                if(y==m-1) code<<=2;
                to.push(code,now.f[i]);
            }
            if(y!=m-1&&Mp[x][y+1]!='X')
            {
                a[y]=0,a[y+1]=val;
                encode(code,a);
                to.push(code,now.f[i]);
            }
        }
        else
        {
            if(a[y]==1&&a[y+1]==2)
            {
                a[y]=a[y+1]=0;
                encode(code,a);
                if(x*m+y>=ex*m+ey&&code==0) ans+=now.f[i];
                continue;
            }
            Merge(a,y);
            encode(code,a);
            if(y==m-1) code<<=2;
            to.push(code,now.f[i]);
        }
    }
}
void dpblank(int x,int y,int cur)
{
    int a[20];
    ll code;
    HASHMAP &to=hm[cur^1];
    HASHMAP &now=hm[cur];
    dpplant(x,y,cur);
    for(int i=0;i<now.size;i++)
    {
        code=now.state[i];
        uncode(code,a);
        if(a[y]||a[y+1]) continue;
        if(y==m-1) code<<=2;
        to.push(code,now.f[i]);
    }
}
void dpblock(int x,int y,int cur)
{
    int a[20];
    ll code;
    HASHMAP &to=hm[cur^1];
    HASHMAP &now=hm[cur];
    for(int i=0;i<now.size;i++)
    {
        code=now.state[i];
        if(y==m-1) code<<=2;
        to.push(code,now.f[i]);
    }
}
void solve()
{
    int cur=0;
    ans=0;
    hm[cur].init();
    hm[cur].push(0,1);
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
    {
        hm[cur^1].init();
        if(Mp[i][j]=='*') dpblank(i,j,cur);
        else if(Mp[i][j]=='O') dpplant(i,j,cur);
        else dpblock(i,j,cur);
        cur^=1;
    }
}
int main()
{
    int t,tt=0;
    scanf("%d",&t);
    while(t--)
    {

        scanf("%d%d",&n,&m);
        ex=ey=-1;
        getchar();
        for(int i=0; i<n; i++) gets(Mp[i]);
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
        {
            if(Mp[i][j]=='O') ex=i,ey=j;
        }
        solve();
        printf("Case %d: %I64d\n",++tt,ans);
    }
}