插头dp

我也来写一写总结,虽然我只做了那道例题和第一题(还没改过),

$Eat The Trees$是一道板子题,但是代码实现还是有点东西的,个人感受。。

丢一波代码:

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#define int long long
#define Maxn 150
#define Sum ((1<<(m+1))-1)
#define Reg register
using namespace std;
int t,n,m,pos,ans,A[Maxn][Maxn],f[3][1<<15];
signed main()
{
    scanf("%lld",&t);
    for(Reg int o=1;o<=t;++o)
    {
        ans=pos=0;
        int sum=0;
        scanf("%lld%lld",&n,&m);
        for(Reg int i=1;i<=n;++i)
        {
            for(Reg int j=1;j<=m;++j)
            {
                scanf("%lld",&A[i][j]);
                if(A[i][j]) ++sum;
            }
        }
        if(sum%2!=0) {printf("Case %lld: There are 0 ways to eat the trees.\n",o); continue;}
        for(Reg int i=0;i<=Sum;++i) f[0][i]=f[1][i]=0;
        f[0][0]=1;
        for(Reg int i=1;i<=n;++i)
        {
            for(Reg int j=1,cur,pre;j<=m;++j)
            {
                ++pos;
                cur=pos&1,pre=(pos+1)&1;
                //清空
                for(Reg int state=0;state<=Sum;++state) f[cur][state]=0;
                //更新
                for(Reg int state=0;state<=Sum;++state)
                {
                    if(j==1) //是第一个格点
                    {
                        //如果最高位是1,不合条件,跳过
                        if((state&(1<<m))!=0) continue;
                        //如果是障碍
                        if(A[i][j]==0) {if((state&1)==0) f[cur][state<<1]+=f[pre][state];}
                        //不是障碍
                        else
                        {
                            //有上插头 只能接1个
                            if((state&1)!=0)
                            {
                                f[cur][((state^1)<<1)|1]+=f[pre][state];
                                f[cur][state<<1]+=f[pre][state];
                            }
                            //没有上插头 只能接2个
                            else f[cur][(state<<1)|3]+=f[pre][state];
                        }
                    }
                    else if(j==m) //是最后一个格点
                    {
                        //如果是障碍
                        if(A[i][j]==0) {if((state&(1<<m))==0&&(state&(1<<(m-1)))==0) f[cur][state]+=f[pre][state];}
                        //不是障碍
                        else
                        {
                            //有左插头和上插头 更新答案或直接转移
                            if((state&(1<<(m-1)))!=0&&(state&(1<<m))!=0)
                                f[cur][(state^(1<<j))^(1<<(j-1))]+=f[pre][state];
                            //只有上插头 只能向下 把最高位置成0
                            else if((state&(1<<(m-1)))==0&&(state&(1<<m))!=0) f[cur][(state^(1<<m))|(1<<(m-1))]+=f[pre][state];
                            //只有左插头 也是只能向下
                            else if((state&(1<<(m-1)))!=0&&(state&(1<<m))==0) f[cur][state]+=f[pre][state];
                            //都没有 不合法 跳过
                            else continue;
                        }
                    }
                    else //是中间格点
                    {
                        //如果是障碍
                        if(A[i][j]==0) {if((state&(1<<j))==0&&(state&(1<<(j-1)))==0) f[cur][state]+=f[pre][state];}
                        //不是障碍
                        else
                        {
                            //如果只有上插头 可以往下接 往右接
                            if((state&(1<<j))!=0&&(state&(1<<(j-1)))==0)
                            {
                                //往下接 在j位置改为1 在j+1位置改为0
                                f[cur][(state|(1<<(j-1)))^(1<<j)]+=f[pre][state];
                                //往右接 不更改j位置和j+1位置(本来就是0或1)
                                f[cur][state]+=f[pre][state];
                            }
                            //如果只有左接头 仍然
                            else if((state&(1<<j))==0&&(state&(1<<(j-1)))!=0)
                            {
                                //往下接 不更改
                                f[cur][state]+=f[pre][state];
                                //往右接 在j位置改为0 在j+1位置改为1
                                f[cur][(state|(1<<j))^(1<<(j-1))]+=f[pre][state];
                            }
                            //如果都有 不增加新插头 直接转移
                            else if((state&(1<<j))!=0&&(state&(1<<(j-1)))!=0)
                                f[cur][(state^(1<<j))^(1<<(j-1))]+=f[pre][state];
                            //如果都没有 接右和下
                            else f[cur][(state|(1<<j))|(1<<(j-1))]+=f[pre][state];
                        }
                    }
                }
            }
        }
        printf("Case %lld: There are %lld ways to eat the trees.\n",o,f[pos&1][0]);
    }
    return 0;
}

然后就是第一道Ural 1519 Formula 1,

题目大意就是求所有的哈密顿回路的个数。

跟上一道题差不多,然后要新加一个3插头。

具体看代码($TLE$),没过

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#define Maxn 30
#define Sum ((1<<((m+1)*2))-1)
#define Reg register
using namespace std;
bool vis[2][44739243];
int t,n,m,pos,lasx=0,lasy=0,ok=0,A[Maxn][Maxn],stack[2][4782969];
long long ans,f[2][44739243];
string s;
inline int get(int state,int pos) {return ((state>>((pos-1)*2))&3);} //查询
inline int change(int state,int pos,int num) {return (((3<<((pos-1)*2)^(state|(3<<((pos-1)*2))))|(num<<((pos-1)*2))));} //更改
inline int update1(int state,int num,int pos) //寻找左括号并更改为右括号
{
    if(get(state,pos)==1) --num; //左括号
    else if(get(state,pos)==2) ++num; //右括号
    if(num==0) return change(state,pos,2);
    else return update1(state,num,pos-1);
}
inline int update2(int state,int num,int pos) //寻找右括号并更改为左括号
{
    if(get(state,pos)==1) ++num; //左括号
    else if(get(state,pos)==2) --num; //右括号
    if(num==0) return change(state,pos,1);
    else return update2(state,num,pos+1);
}
inline void insert(int cur,int num)
{
    if(f[cur][num]==0) return;
    if(!vis[cur][num])
    {
        vis[cur][num]=1;
        stack[cur][++stack[cur][0]]=num;
    }
    return;
}
signed main()
{
//    freopen("text.in","r",stdin);
    scanf("%d%d",&n,&m);
    for(Reg int i=1;i<=n;++i)
    {
        cin>>s;
        for(Reg int j=1;j<=m;++j)
        {
            if(s[j-1]=='*') A[i][j]=0;
            else
            {
                A[i][j]=1;
                lasx=i,lasy=j;
            }
        }
    }
    f[0][0]=1,vis[0][0]=1,stack[0][++stack[0][0]]=0;
    for(Reg int i=1;i<=n;++i)
    {
        for(Reg int j=1,cur,pre;j<=m;++j)
        {
            ++pos; cur=pos&1,pre=(pos+1)&1;
            for(Reg int k=1;k<=stack[cur][0];++k) f[cur][stack[cur][k]]=vis[cur][stack[cur][k]]=0; //清空
            stack[cur][0]=0;
            if(ok) break;
            for(Reg int k=1,state;k<=stack[pre][0];++k) //转移
            {
                state=stack[pre][k];
                if(j==1) //第一个格子
                {
                    if(get(state,m+1)!=0) continue;
                    int plug=get(state,1);
                    if(A[i][j]==0)
                    {
                        if(plug==0)
                        {
                            f[cur][state<<2]+=f[pre][state];
                            insert(cur,state<<2);
                        }
                    } //障碍 不能有插头
                    else //不是障碍
                    {
                        if(plug==1) //1插头
                        {
                            f[cur][state<<2]+=f[pre][state]; //新建向右的1插头
                            f[cur][change(change(state,1,0)<<2,1,1)]+=f[pre][state]; //新建向下的1插头
                            insert(cur,state<<2);
                            insert(cur,change(change(state,1,0)<<2,1,1));
                        }
                        else if(plug==2) //2插头
                        {
                            f[cur][state<<2]+=f[pre][state]; //新建向右的2插头
                            f[cur][change(change(state,1,0)<<2,1,2)]+=f[pre][state]; //新建向下的2插头
                            insert(cur,state<<2);
                            insert(cur,change(change(state,1,0)<<2,1,2));
                        }
                        else if(plug==0) //无插头 要新建2个插头 一个1插头一个2插头
                        {
                            f[cur][change(change(state<<2,1,1),2,2)]+=f[pre][state]; //新建向右的2插头和向下的1插头
                            insert(cur,change(change(state<<2,1,1),2,2));
                        }
                    }
                }
                else if(j==m) //最后一个格子
                {
                    int plug1=get(state,m),plug2=get(state,m+1);
                    if(A[i][j]==0) //障碍
                    {
                        if(plug1==0&&plug2==0)
                        {
                            f[cur][state]+=f[pre][state];
                            insert(cur,state);
                        }
                    }
                    else //不是障碍
                    {
                        if(plug1==1&&plug2==2) //左插头为1插头 上插头为2插头 匹配 直接转移
                        {
                            if(i==lasx&&j==lasy)
                            {
                                if((change(change(state,m,0),m+1,0))==0) ans+=f[pre][state]; //累加
                                ok=1;
                                continue;
                            }
                        }
                        else if(plug1==1&&plug2==1) //左插头为1插头 上插头为1插头 没有这种情况
                            continue;
                        else if(plug1==2&&plug2==2) //左插头为2插头 上插头为2插头 更新状态
                        {
                            int p=update1(state,0,m);
                            p=change(change(p,m,0),m+1,0);
                            f[cur][p]+=f[pre][state];
                            insert(cur,p);
                        }
                        else if(plug1!=0&&plug2==0) //左插头为1/2插头 无上插头 直接转移
                        {
                            f[cur][state]+=f[pre][state];
                            insert(cur,state);
                        }
                        else if(plug1==0&&plug2!=0) //无左插头 上插头为1/2插头 删掉最高位然后更改
                        {
                            int kind=plug2;
                            f[cur][change(change(state,m+1,0),m,kind)]+=f[pre][state];
                            insert(cur,change(change(state,m+1,0),m,kind));
                        }
                        else if(plug1==0&&plug2==0) //不存在
                            continue;
                    }
                }
                else //为中间的格子
                {
                    int plug1=get(state,j),plug2=get(state,j+1);
                    if(A[i][j]==0) //障碍
                    {
                        if(plug1==0&&plug2==0)
                        {
                            f[cur][state]+=f[pre][state];
                            insert(cur,state);
                        }
                    }
                    else //不是障碍
                    {
                        if(plug1==0&&plug2==0) //无插头
                        {
                            f[cur][change(change(state,j+1,2),j,1)]+=f[pre][state]; //新建向右的2插头和向下的1插头
                            insert(cur,change(change(state,j+1,2),j,1));
                        }
                        else if(plug1==1&&plug2==2) //左插头为1插头 上插头为2插头 更新状态
                        {
                            if(i==lasx&&j==lasy)
                            {
                                ans+=f[pre][state];
                                ok=1;
                                continue;
                            }
                        }
                        else if(plug1==1&&plug2==1) //左插头为1插头 上插头为1插头
                        {
                            int p=update2(state,0,j+1);
                            p=change(change(p,j,0),j+1,0);
                            f[cur][p]+=f[pre][state];
                            insert(cur,p);
                        }
                        else if(plug1==2&&plug2==1) //左插头为2插头 上插头为1插头
                        {
                            f[cur][change(change(state,j,0),j+1,0)]+=f[pre][state];
                            insert(cur,change(change(state,j,0),j+1,0));
                        }
                        else if(plug1==2&&plug2==2) //左插头为2插头 上插头为2插头
                        {
                            int p=update1(state,0,j);
                            p=change(change(p,j,0),j+1,0);
                            f[cur][p]+=f[pre][state];
                            insert(cur,p);
                        }
                        else if(plug1>0&&plug2==0) //左插头为1/2插头 无上插头
                        {
                            int kind=plug1;
                            f[cur][state]+=f[pre][state]; //新建向下的1/2插头
                            f[cur][change(change(state,j,0),j+1,kind)]+=f[pre][state]; //新建向右的1/2插头
                            insert(cur,state);
                            insert(cur,change(change(state,j,0),j+1,kind));
                        }
                        else if(plug1==0&&plug2>0) //无左插头 上插头为1/2插头
                        {
                            int kind=plug2;
                            f[cur][change(change(state,j+1,0),j,kind)]+=f[pre][state]; //新建向下的1/2插头
                            f[cur][state]+=f[pre][state]; //新建向右的1/2插头
                            insert(cur,state);
                            insert(cur,change(change(state,j+1,0),j,kind));
                        }
                    }
                }
            }
        }
    }
    printf("%lld\n",ans);
    return 0;
}

 

posted @ 2019-07-29 14:35  Milk_Feng  阅读(115)  评论(0编辑  收藏  举报