ural 1519 Formula 1

题目链接http://acm.timus.ru/problem.aspx?space=1&num=1519

题目分类:插头dp

题意:求经过所有可行点的哈密顿回路的个数  * 不可走 . 可以走  2 ≤ NM ≤ 12

代码

括号匹配法,转移有点复杂,但是时间空间比较小 

#include<bits/stdc++.h>

#define LL long long
using namespace std;
const int maxn=30001;
int n,m,now,pre;
int mov[13]={0,2,4,6,8,10,12,14,16,18,20,22,24};//根据进制选择移位距离
char gp[20][20],fx,fy;//存图,最后一个可行点的坐标
inline int getbit(LL st,int k){ return (st>>mov[k])&3;}//获得第k位的状态
inline int pybit(LL st,int k){ return st<<mov[k];}     //平移k位
inline LL clrbit(LL st,int i,int j){ return st&(~(3<<mov[i]))&(~(3<<mov[j]));}//清空第i位和第j位
struct node//状态离散hash
{
    int head[maxn],next[maxn],size;
    LL sum[maxn],sta[maxn];//保存所求和及状态
    void clear()
    {
        memset(head,-1,sizeof(head));
        memset(sum,0,sizeof(sum));
        size=0;
    }
    void push(LL st,const LL v)
    {
        LL hash=st%maxn;
        for(int i=head[hash];i>=0;i=next[i])
        {
            if(sta[i]==st)
            {
                sum[i]+=v;
                return;
            }
        }
        sta[size]=st,sum[size]=v;
        next[size]=head[hash],head[hash]=size++;
    }
}dp[2];
inline int fl(LL st,int pos)//从左往右找到和当前pos位置匹配的右括号
{
    int cnt=1;
    for(int i=pos+1;i<=m;i++)
    {
        int k=getbit(st,i);
        if(k==1) cnt++;
        else if(k==2) cnt--;
        if(!cnt) return i;
    }
}
inline int fr(LL st,int pos)//从右往左找到和当前pos位置匹配的左括号
{
    int cnt=1;
    for(int i=pos-1;i>=0;i--)
    {
        int k=getbit(st,i);
        if(k==2) cnt++;
        else if(k==1) cnt--;
        if(!cnt) return i;
    }
}
void DP(int x,int y,int k)//每种状态的转移,根据需要修改
{
    int l=getbit(dp[pre].sta[k],y-1);
    int up=getbit(dp[pre].sta[k],y);
    LL st=clrbit(dp[pre].sta[k],y-1,y);
    LL v=dp[pre].sum[k];
    if(!l&&!up)
    {
        if(gp[x][y]=='*')
        {
            dp[now].push(st,v);
            return;
        }
        if(x<n&&y<m&&gp[x+1][y]=='.'&&gp[x][y+1]=='.')
            dp[now].push(st|pybit(1,y-1)|pybit(2,y),v);
    }
    else if(!l||!up)
    {
        int e=l+up;
        if(x<n&&gp[x+1][y]=='.')
            dp[now].push(st|pybit(e,y-1),v);
        if(y<m&&gp[x][y+1]=='.')
            dp[now].push(st|pybit(e,y),v);
    }
    else if(l==1&&up==1)
        dp[now].push(st^pybit(3,fl(st,y)),v);
    else if(l==2&&up==2)
        dp[now].push(st^pybit(3,fr(st,y-1)),v);
    else if(l==2&&up==1)
        dp[now].push(st,v);
    else if(x==fx&&y==fy)
        dp[now].push(st,v);
}
LL solve()
{
    dp[0].clear();//初状态
    dp[0].push(0,1);
    now=0,pre=1;
    for(int i=1;i<=n;i++)//逐格逐状态枚举
    {
        pre=now,now^=1,dp[now].clear();
        for(int k=0;k<dp[pre].size;k++)//轮廓线下移对齐
            dp[now].push(pybit(dp[pre].sta[k],1),dp[pre].sum[k]);
        for(int j=1;j<=m;j++)
        {
            pre=now,now^=1,dp[now].clear();
            for(int k=0;k<dp[pre].size;k++)
            {
                DP(i,j,k);
            }
        }
    }
    for(int i=0;i<dp[now].size;i++)//寻找最终答案
        if(dp[now].sta[i]==0)
            return dp[now].sum[i];
    return 0;
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        for(int i=1;i<=n;i++)//都是从1开始的
            scanf("%s",&gp[i][1]);
        fx=0;
        for(int i=n;i>0&&!fx;i--)//寻找最后一个可行点
        {
            for(int j=m;j>0&&!fx;j--)
            {
                if(gp[i][j]=='.')
                    fx=i,fy=j;
            }
        }
        if(fx==0) puts("0");
        else cout<<solve()<<endl;
    }
    return 0;
} 

最小表示法,转移简单,时间空间较大

#include<bits/stdc++.h>

#define LL long long  
using namespace std;  
const int maxn=30001,inc=3,bit=7;//3位二进制以及111的表示  
int n,m,now,pre,code[20],bin[20],res[20];//用来表示状态的每一位的数值  
char gp[20][20],fx,fy;//图和最后的可行点  
struct node//离散化hash  
{  
    int head[maxn],next[maxn],size;  
    LL sum[maxn],sta[maxn];  
    void clear()  
    {  
        memset(head,-1,sizeof(head));  
        size=0;  
    }  
    void push(LL st,const LL v)  
    {  
        LL hash=st%maxn;  
        for(int i=head[hash];i>=0;i=next[i])  
        {  
            if(sta[i]==st)  
            {  
                sum[i]+=v;  
                return ;  
            }  
        }  
        sta[size]=st,sum[size]=v;  
        next[size]=head[hash],head[hash]=size++;  
    }  
}dp[2];  
inline LL encode(int m)//将code转换成状态  
{  
    LL st=0;  
    int cnt=1;  
    memset(bin,-1,sizeof(bin));  
    bin[0]=0;  
    for(int i=m;i>=0;i--)  
    {  
        if(bin[code[i]]==-1)  
            bin[code[i]]=cnt++;  
        code[i]=bin[code[i]];  
        st<<=inc;  
        st|=code[i];  
    }  
    return st;  
}  
inline void decode(LL st,int m)//将状态转换成code  
{  
    for(int i=0;i<=m;i++)  
    {  
        code[i]=st&bit;  
        st>>=inc;  
    }  
}  
void DP(int x,int y,int k)//dp具体情况具体分析  
{  
    decode(dp[pre].sta[k],m);  
    int l=code[y-1];  
    int up=code[y];  
    code[y-1]=code[y]=0;  
    memcpy(res,code,sizeof(code));  
    LL v=dp[pre].sum[k];  
    if(!l&&!up)  
    {  
        if(gp[x][y]=='*')  
            dp[now].push(encode(m),v);  
        else if(x<n&&y<m&&gp[x+1][y]=='.'&&gp[x][y+1]=='.')  
        {  
            code[y]=code[y-1]=bit;  
            dp[now].push(encode(m),v);  
        }  
    }  
    else if(!l||!up)  
    {  
        int e=l+up;  
        if(x<n&&gp[x+1][y]=='.')  
        {  
            code[y-1]=e;  
            dp[now].push(encode(m),v);  
            memcpy(code,res,sizeof(res));  
        }  
        if(y<m&&gp[x][y+1]=='.')  
        {  
            code[y]=e;  
            dp[now].push(encode(m),v);  
        }  
    }  
    else if(l!=up)  
    {  
        for(int i=0;i<=m;i++)  
            if(code[i]==up)  
                code[i]=l;  
        dp[now].push(encode(m),v);  
    }  
    else if(x==fx&&y==fy)  
        dp[now].push(encode(m),v);  
}  
LL solve()  
{  
    dp[0].clear();//初始化状态  
    dp[0].push(0,1);  
    now=0,pre=1;  
    for(int i=1;i<=n;i++)//逐格逐状态枚举转移  
    {  
        pre=now,now^=1,dp[now].clear();  
        for(int k=0;k<dp[pre].size;k++)//轮廓线行转移  
            dp[now].push(dp[pre].sta[k]<<inc,dp[pre].sum[k]);  
        for(int j=1;j<=m;j++)  
        {  
            pre=now,now^=1,dp[now].clear();  
            for(int k=0;k<dp[pre].size;k++)  
            {  
                DP(i,j,k);  
            }  
        }  
    }  
    for(int i=0;i<dp[now].size;i++)  
        if(dp[now].sta[i]==0)  
            return dp[now].sum[i];  
    return 0;  
}  
int main()  
{  
    while(~scanf("%d%d",&n,&m))  
    {  
        for(int i=1;i<=n;i++)//都是从1开始  
            scanf("%s",&gp[i][1]);  
        fx=fy=0;  
        for(int i=n;i>0&&!fx;i--)//寻找最终的位置  
            for(int j=m;j>0&!fx;j--)  
                if(gp[i][j]=='.')  
                    fx=i,fy=j;  
        if(fx==0)puts("0");  
        else cout<<solve()<<endl;  
    }  
}  
  
anytime you feel the pain.hey,refrain.don't carry the world upon your shoulders
原文地址:https://www.cnblogs.com/gaoss/p/4967882.html