bzoj 1948 [Ceoi2006]Connect 插头dp

这篇博客介绍了Ceoi2006竞赛中的一道题目,涉及插头动态规划(DP)的解题思路。通过将障碍视为边框,并计算跨过边框的步数,来维护轮廓线上插头位置的状态。博主指出,由于题目允许任意匹配,因此不需要记录插头的具体匹配情况。解题策略是使用f[i][j][k]的状态转移方程,表示到达点(i, j)且轮廓线状态为k的最小步数。" 122993611,9737436,Appium 并发测试:多设备与多进程启动实践,"['python', '自动化测试', '功能测试', '测试工具', '开发语言']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

#include <bits/stdc++.h>
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)<<m;
    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;i<n;i+=2)
        for(int j=2;j<m;j+=2)
            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<<m+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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值