FZU 1977 Pandora adventure 插头dp

题目链接

题意:

有些格子必须访问,有些格子不能访问,有些格子可以访问。
只能形成一个环。问线路的数量。

解:

之前做的一道题是要么可以访问,要么不能访问。区别是这个题

需要记录回路是否已经闭合。直接加在状态里即可。

而且必须要记录是否闭合!!!

1.这题时间卡的太紧,用stl模拟链地址法还是会超时。

2.行末shift()容易掉。

3.如果已经形成了闭合回路,当前格可能仍会有上插头或者左插头。这点非常重要。如果只能形成一个回路,而且必须在最后一个非障碍格子闭合,则不用考虑这些。

4.fzu用%lld 根本不行,要用%I64d,以后还是多用cin,cout

这里写图片描述

实际上只用判断是否有上插头即可,不可能已有线路闭合且有左插头。


代码:

#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;

#define all(x) (x).begin(), (x).end()
#define for0(a, n) for (int (a) = 0; (a) < (n); (a)++)
#define for1(a, n) for (int (a) = 1; (a) <= (n); (a)++)
#define mes(a,x,s)  memset(a,x,(s)*sizeof a[0])
#define mem(a,x)  memset(a,x,sizeof a)
#define ysk(x)  (1<<(x))
typedef long long ll;
const int INF =0x3f3f3f3f;
const int maxn=12    ;
const int N=500000    ;
const int mod=19993   ;
int n,m,cur;
int a[maxn+3][maxn+3];

struct pll
{
    ll first,second;
};
struct Hashmap
{
    pll G[N];
    int nex[N],fir[mod+5],nedge;

    void insert(ll s,ll val)
    {
        int p=s%mod;
        for(int i=fir[p];~i;i=nex[i])
        {
            if(G[i].first==s)
            {
                G[i].second+=val;
                return;
            }
        }
        G[nedge].first=s;
        G[nedge].second=val;
        nex[nedge]=fir[p];
        fir[p]=nedge++;
    }
    void init()
    {
        nedge=0;
        mem(fir,-1);
    }

}hashmap[2];
struct Code
{
    int bit[maxn+3],ended,ch[maxn+3],tot;
    ll s;
    void decode(ll x)
    {
        tot=0;
        for0(i,m+1)
        {
            bit[i]=x&7;
            tot=max(tot,bit[i]);
            x>>=3;
        }
        ended=x&1;
        tot++;
    }
    ll normalize()
    {
        mem(ch,-1);ch[0]=0;tot=1;
        s=ended;
        for(int i=m;i>=0;i--)
        {
            if(~ch[bit[i]])  bit[i]=ch[bit[i] ];
            else
            {
                bit[i]=ch[bit[i]]=tot++;
            }
            s=(s<<3)|bit[i];
        }
        return s;
    }
    void shift()
    {
        for(int i=m;i>=1;i--)  bit[i]=bit[i-1];
        bit[0]=0;
    }
    void color(int a,int b)
    {
        for0(i,m+1)  if(bit[i]==a) bit[i]=b;
    }

}code;


void dpBlock(int x,int y,ll state,ll val)
{
    if(y==m)  code.shift();
    hashmap[cur].insert(code.normalize(),val);

}


void dpBlank(int x,int y,ll state,ll val)
{
    const int p=code.bit[y-1],q=code.bit[y];
    if(code.ended)
    {
        if(p||q||a[x][y]==2)  return;//****
        if(y==m)  code.shift();
        hashmap[cur].insert(code.normalize(),val);
        return;
    }
    if(p&&q)
    {
        if(p==q)
        {
           code.bit[y-1]=code.bit[y]=0;
           if(y==m) code.shift();
           code.ended=1;
           hashmap[cur].insert(code.normalize(),val);
        }
        else
        {
            code.color(p,q);
            code.bit[y-1]=code.bit[y]=0;
            if(y==m) code.shift();
            hashmap[cur].insert(code.normalize(),val);
        }
        return;
    }
    if(p||q)
    {
        int t=p+q;
        if(a[x][y+1])
        {
           code.bit[y-1]=0,code.bit[y]=t;
           hashmap[cur].insert(code.normalize(),val);
        }
        if(a[x+1][y])
        {
           code.bit[y-1]=t,code.bit[y]=0;
           if(y==m) code.shift();
           hashmap[cur].insert(code.normalize(),val);
        }
        return;
    }
    if(!p&&!q)
    {
       if(a[x][y+1]&&a[x+1][y])
       {
           code.bit[y-1]=code.bit[y]=code.tot++;
           hashmap[cur].insert(code.normalize(),val);
       }
       if(a[x][y]==1)
       {
           code.bit[y-1]=code.bit[y]=0;
           if(y==m) code.shift();
           hashmap[cur].insert(code.normalize(),val);
       }
       return;
    }


}


void solve()
{
    cur=0;
    hashmap[cur].init();
    hashmap[cur].insert(0,1);
    for1(i,n) for1(j,m)
    {
        cur^=1;hashmap[cur].init();
        for0(k,mod)  for(int l=hashmap[cur^1].fir[k];~l;l=hashmap[cur^1].nex[l])
        {
            pll now=hashmap[cur^1].G[l];
            ll state=now.first;
            ll val=now.second;
            code.decode(state);
            if(!a[i][j]) dpBlock(i,j,state,val);
            else    dpBlank(i,j,state,val);
        }
    }
    ll ans=0;
    for0(k,mod)  for(int l=hashmap[cur].fir[k];~l;l=hashmap[cur].nex[l]) ans+=hashmap[cur].G[l].second;
    cout<<ans<<endl;
}

int main()
{
   int T,kase=0;cin>>T;
   while(T--)
   {
       cin>>n>>m;
       mem(a,0);char ch;
       for1(i,n) for1(j,m)
       {
           cin>>ch;
           if(ch=='X') a[i][j]=0;
           else if(ch=='*')  a[i][j]=1;
           else a[i][j]=2;
       }
       cout<<"Case "<<++kase<<": ";
       solve();

   }
   return 0;
}
/*
12 12
OOOOOOOOOOOO
OOOOOOOOOOOO
OOOOOOOOOOOO
OOOOOOOOOOOO
OOOOOOOOOOOO
OOOOOOOOOOOO
OOOOOOOOOOOO
OOOOOOOOOOOO
OOOOOOOOOOOO
OOOOOOOOOOOO
OOOOOOOOOOOO
OOOOOOOOOOOO

1076226888605605706


12 12
************
************
************
************
************
************
************
************
************
************
************
************

12 12
O**********O
************
************
************
************
************
************
************
************
************
************
O**********O
771046925528298786

 12 12
O**********O
************
*******O****
************
************
*****O******
************
************
*******O****
************
************
O**********O
6395622514350385989

4 4
XXXX
X*OX
XO*X
XXXX


3234
6 6
******
******
******
******
******
******
1222364

*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值