URAL 1519 Formula 1 【插头DP模板题】


题意:

题意就是给出一个带障碍的n*m的格子,求有多少条回路恰好经过每个非障碍格子一次?

思路:

插头DP学自 插头DP
写这道题的时候几个地方处理不当,调了许久的bug。

代码:(最小表示法)

#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=1000010;
struct HASHMAP
{
    int head[HASH],next[STATE],size;
    long long state[STATE];
    long long 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;
void encode(ll &code,int a[])
{
    code=0;
    for(int i=m; i>=0; i--)
    {
        code<<=3;
        code|=(ll)a[i];
    }
}
void uncode(ll code,int a[])
{
    for(int i=0; i<=m; i++)
    {
        a[i]=code&7;
        code>>=3;
    }
}
void add(int a[],int c)
{
    int val=1;
    for(int i=0; i<c; i++) val=max(val,a[i]+1);
    for(int i=c+1; i<=m; i++) if(a[i]>=val) a[i]++;
    a[c]=a[c+1]=val;
}
void Merge(int a[],int c)
{
    int val=min(a[c],a[c+1]);
    int Max=max(a[c],a[c+1]);
    a[c]=a[c+1]=0;
    for(int i=0; i<=m; i++) {
        if(a[i]==Max) a[i]=val;
            if(a[i]>Max) a[i]--;
    }
}
void show(int a[])
{
    for(int i=0;i<=m;i++) printf("%d%c",a[i],i==m?'\n':' ');
}
void dpblank(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]=='*'||Mp[x][y+1]=='*') continue;
            add(a,y);
            encode(code,a);
            if(y==m-1) code<<=3;
            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]=='.')
            {
                a[y]=val,a[y+1]=0;
                encode(code,a);
                if(y==m-1) code<<=3;
                to.push(code,now.f[i]);
            }
            if(y!=m-1&&Mp[x][y+1]=='.')
            {
                a[y]=0,a[y+1]=val;
                encode(code,a);
                to.push(code,now.f[i]);
            }
        }
        else
        {
            if(a[y]==a[y+1]&&!(x==ex&&y==ey)) continue;
            Merge(a,y);
            encode(code,a);
            if(y==m-1) code<<=3;
            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<<=3;
        to.push(code,now.f[i]);
    }
}
void solve()
{
    int cur=0;
    ll 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 dpblock(i,j,cur);
        cur^=1;
    }
    int a[20];
    if(hm[cur].size) ans=hm[cur].f[0];
    printf("%I64d\n",ans);
}
int main()
{
    while(~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]=='.') ex=i,ey=j;
        }
        if(ex<0){puts("0");continue;}
        solve();
    }
}

代码2:(括号表示法)

#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=1000010;
struct HASHMAP
{
    int head[HASH],next[STATE],size;
    long long state[STATE];
    long long 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;
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 dpblank(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]=='*'||Mp[x][y+1]=='*') 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]=='.')
            {
                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]=='.')
            {
                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&&!(x==ex&&y==ey)) continue;
//            cout<<x<<' '<<y<<endl;
//            show(a);
            Merge(a,y);
//            show(a);
//            puts("---------------");
            encode(code,a);
            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;
    ll 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 dpblock(i,j,cur);
        cur^=1;
    }
    int a[20];
    if(hm[cur].size) ans=hm[cur].f[0];
    printf("%I64d\n",ans);
}
int main()
{
    while(~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]=='.') ex=i,ey=j;
        }
        if(ex<0){puts("0");continue;}
        solve();
    }
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值