bzoj 1948 [Ceoi2006]Connect 插头dp

啊,就是插头dp啦。其实这道算是水一点的。。。
把障碍的行和列当成格子的边框。不过统计步数时注意跨过边框算一步。
维护一下轮廓线上有插头的位置。由于这道题随便两个都可以匹配所以根本不需要记插头的匹配。
f[i][j][k] 表示现在到点(i,j)轮廓线上状态为k的最小步数。然后逐格转移就好了。

#include 
using namespace std;
int dx[4]={0,-1,0,1};
int dy[4]={-1,0,1,0};
int n,m,inf,cnt;
char s1[31][110],s[110][31];
int f[2][26][(1<<13)+10],blo[110][31][4];
void upd(int &x,int y){x=min(x,y);}
int trs(int x,int y)
{
    x=(x>>2)<<1;x|=y&1;
    x|=((y&2)>>1)<return x;
}
int main()
{
    //freopen("tt.in","r",stdin);
    scanf("%d%d",&n,&m);gets(s1[0]+1);
    for(int i=1;i<=n;i++)gets(s1[i]+1);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            s[j][i]=s1[i][j],cnt+=(s1[i][j]=='X');
    swap(n,m);
    for(int i=2;i2)
        for(int j=2;j2)
            for(int k=0;k<4;k++)
                blo[i>>1][j>>1][k]=(s[i+dy[k]][j+dx[k]]!=' ');
    n/=2;m/=2;
    memset(f[1],0x3f,sizeof(f[1]));
    inf=f[1][1][0];f[1][1][0]=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {   
            if(j==m)
                memset(f[~i&1],0x3f,sizeof(f[~i&1]));
            for(int k=0;k<1<1;k++)
            {
                if(f[i&1][j][k]==inf)continue;
                int *nex;
                if(j==m)nex=f[~i&1][1];
                else nex=f[i&1][j+1];
                int v1=blo[i][j][2],v2=blo[i][j][3],val=f[i&1][j][k];
                if(s[i<<1][j<<1]=='X')
                {
                    if((k&3)==3)continue;
                    if((k&3)==0)
                    {
                        if(!v2)upd(nex[trs(k,1)],val+1);
                        if(!v1)upd(nex[trs(k,2)],val+1);
                    }
                    else upd(nex[trs(k,0)],val);
                }
                else
                {
                    if((k&3)==3)upd(nex[trs(k,0)],val+1);
                    else if((k&3)==0)
                    {
                        upd(nex[trs(k,0)],val);
                        if(!v1&&!v2)upd(nex[trs(k,3)],val+3);
                    }
                    else
                    {
                        if(!v2)upd(nex[trs(k,1)],val+2);
                        if(!v1)upd(nex[trs(k,2)],val+2);
                    }
                }
            }
        }
    printf("%d\n",f[(n+1)&1][1][0]+cnt/2);
    return 0;
}

你可能感兴趣的:(dp)