bzoj1187: [HNOI2007]神奇游乐园 & bzoj2310: ParkII

觉得这两道题完全可以写在一起,虽然看起来有点乱,但分开真没什么好写的。


bzoj1187: [HNOI2007]神奇游乐园
题意:在n*m的网格图内找一条简单回路使经过的权值和最大,n<=100,m<=6。


[bzoj2310: ParkII]
题意:在n*m的网格图内找一条简单路径使经过的权值和最大,n<=100,m<=8。


题解

非常典型的插头dp。
逐格转移,根据j和j+1位置的插头情况分类讨论。
t1在形成一条回路并且没有其他插头的时候记录答案。
t2涉及独立插头,状态进制加一位就可以。稍稍剪了一下枝但是效果并没有变好


代码

比较麻烦,感觉正常写应该不长这样。

//1187#include<iostream>
#include<cstdio>
#include<cstring>
#define inf -600001
#define sad 5000000
#define UP1 upd(x,y+1,ncal(),val)
#define UP2 shift(),upd(x+1,0,ncal(),val)
using namespace std;
int n,m,a[101][7],ans=inf;
int dp[101][7][2200];
bool inq[101][7][2200];
int q[sad][3],h,t;
int f[7],lk[7],st[5],T,mxm=1,val;
bool test;
void cal(int v)
{
    for(int i=m;i>=0;i--)
    f[i]=v%3,v/=3;
    T=0;
    for(int i=0;i<=m;i++)
    if(f[i]==1)
    st[T++]=i;
    else if(f[i]==2)
    lk[st[--T]]=i,lk[i]=st[T];
}
int ncal()
{
    int ret=0;
    for(int i=0;i<=m;i++)
    ret=ret*3+f[i];
    return ret;
}
void upd(int i,int j,int k,int v)
{
    if(i==n)return;
    if(dp[i][j][k]<v)
    {
        dp[i][j][k]=v;
        if(!ncal())ans=max(ans,v);
        else if(!inq[i][j][k])
        {
            inq[i][j][k]=1,
            q[t][0]=i,q[t][1]=j,q[t++][2]=k;
            if(t==sad)t=0;
        }
    }
}
void shift()
{for(int i=m;i;i--)f[i]=f[i-1];f[0]=0;}
int x,y,z;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<=m;i++)
    mxm*=3;
    for(int i=0;i<n;i++)
    for(int j=0;j<m;j++)
    {
        scanf("%d",&a[i][j]);
        for(int k=0;k<mxm;k++)
        dp[i][j][k]=inf;
    }
    for(int i=0;i<n-1;i++)
    for(int j=1;j<m;j++)
    {
        for(int k=0;k<=m;k++)
        f[k]=0;
        f[j-1]=1,f[j]=2;
        dp[i][j][ncal()]=a[i][j-1];
        q[t][0]=i,q[t][1]=j,q[t++][2]=ncal();
    }
    while(h!=t)
    {
        x=q[h][0],y=q[h][1];
        cal(z=q[h++][2]);
        if(h==sad)h=0;
        inq[x][y][z]=0;
        val=dp[x][y][z]+a[x][y];
        if(f[y]==0&&!f[y+1])
        {
            if(y<m-1)
            upd(x,y+1,z,dp[x][y][z]);
            else if(x<n-1)
            shift(),upd(x+1,0,ncal(),dp[x][y][z]);
            if(x<n-1&&y<m-1)
            f[y]=1,f[y+1]=2,UP1;
        }
        else if(!f[y])
        {
            if(y<m-1)UP1;
            if(x<n-1)
            {
                f[y]=f[y+1],f[y+1]=0;
                if(y==m-1)UP2;
                else UP1;
            }
        }
        else if(!f[y+1])
        {
            if(x<n-1)
            {
                if(y==m-1)UP2;
                else UP1;
            }
            if(y<m-1)
            f[y+1]=f[y],f[y]=0,UP1;
        }
        else if(f[y]==f[y+1])
        {
            f[y]=f[y+1]=0;
            f[lk[y]]=2,f[lk[y+1]]=1;
            if(y<m-1)UP1;
            else if(x<n-1)UP2;
        }
        else if(f[y]==2&&f[y+1]==1)
        {
            f[y]=f[y+1]=0;
            if(y<m-1)UP1;
            else if(x<n-1)UP2;
        }
        else
        {
            x=0;
            for(int i=0;i<=m;i++)
            if(f[i])x++;
            if(x==2&&ans<val)
            ans=val;
        }
    }
    printf("%d",ans);
}
//2310:
#include<cstdio>
#include<cstring>
#define inf 0xefefefef
#define mxs 260000
#define upd if(ans<val)ans=val
using namespace std;
int n,m,ans=inf,tim,T,val,hd;
int dp[mxs][2],q[mxs][2],Tim[mxs];
int a[100][8],f[9],lk[9],t[2]={1},bin[9]={1},st[5];
bool inq[mxs][2],now,sad;
void cal(int S)
{
    hd=T=sad=0;
    if(!S)sad=1;
    for(int i=0;i<=m;i++)
    {
        f[i]=S&3,S>>=2;
        if(f[i]==3)hd++;
        else if(f[i]==1)st[T++]=i,sad=1;
        else if(f[i]==2)lk[i]=st[--T],lk[st[T]]=i,sad=1;
    }
}
int i,j,k,s;
void ad(int S,int v)
{
    if(j==m-1)S<<=2;
    if(dp[S][now^1]<v||Tim[S]<tim)
    {
        dp[S][now^1]=v,Tim[S]=tim;
        if(!inq[S][now^1])
        inq[S][now^1]=1,q[t[now^1]++][now^1]=S;
    }
}
int main()
{
    memset(dp,0xef,sizeof dp);
    scanf("%d%d",&n,&m);
    for(i=1;i<=m;i++)
    bin[i]=(bin[i-1]<<2);
    for(i=0;i<n;i++)
    for(j=0;j<m;j++)
    {scanf("%d",&a[i][j]);if(ans<a[i][j])ans=a[i][j];}
    dp[0][0]=0;
    for(i=0;i<n;i++)
    for(j=0;j<m;j++)
    {
        while(t[now])
        {
            cal(s=q[--t[now]][now]);
            inq[s][now]=0;val=dp[s][now]+a[i][j];
            if(dp[s][now]<=0&&!sad)continue;
            if(!f[j])
            {
                if(!f[j+1])
                {
                    if(j+1<m&i+1<n)
                    ad(s+bin[j]+(bin[j+1]<<1),val);
                    if(i<n-1||j<m-1)
                    ad(s,dp[s][now]);
                    if(a[i][j]>0&&hd<2)
                    {
                        if(j+1<m)ad(s+3*bin[j+1],val);
                        if(i+1<n)ad(s+3*bin[j],val);
                    }
                }
                else
                {
                    if(a[i][j]>0)
                    {
                        if(f[j+1]<3)
                        {
                            if(hd<2)
                            ad(s-f[j+1]*bin[j+1]+(3-f[lk[j+1]])*bin[lk[j+1]],val);
                        }
                        else if(s==f[j+1]*bin[j+1])upd;
                    }
                    if(i+1<n)ad(s+f[j+1]*(bin[j]-bin[j+1]),val);
                    if(j+1<m)ad(s,val);
                }
            }
            else if(!f[j+1])
            {
                if(a[i][j]>0)
                {
                    if(f[j]<3)
                    {
                        if(hd<2)
                        ad(s-f[j]*bin[j]+(3-f[lk[j]])*bin[lk[j]],val);
                    }
                    else if(s==f[j]*bin[j])upd;
                }
                if(i+1<n)ad(s,val);
                if(j+1<m)ad(s+f[j]*(bin[j+1]-bin[j]),val);
            }
            else
            {
                s-=f[j+1]*bin[j+1]+f[j]*bin[j];
                if(f[j]==3)
                {
                    if(f[j+1]<3)
                    ad(s+(3-f[lk[j+1]])*bin[lk[j+1]],val);
                    else if(!s)upd;
                }
                else if(f[j+1]==3)
                ad(s+(3-f[lk[j]])*bin[lk[j]],val);
                else if(f[j]==2)
                {
                    if(f[j+1]==1)ad(s,val);
                    else ad(s+(2-f[lk[j]])*bin[lk[j]],val);
                }
                else if(f[j+1]==1)
                ad(s+(1-f[lk[j+1]])*bin[lk[j+1]],val);
            }
        }
        tim++;now^=1;
    }
    printf("%d",ans);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值