zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    PDO扩展
    阿里云ECS VSFTP上传本地文件
    Nginx+lua_Nginx+GraphicsMagick来实现实时缩略图
    Mysql 5.6主从同步配置与解决方案
    windows安装配置mongodb及图形工具MongoVUE
    安装phpredis扩展以及phpRedisAdmin工具
    Redis安装配置以及开机启动
    CentOS安装Git服务器 Centos 6.5 + Git 1.7.1.0 + gitosis
    OpenStack 入门3
    Openstack 入门2
  • 原文地址:https://www.cnblogs.com/gaoss/p/4967882.html
Copyright © 2011-2022 走看看