cf761 Round #394 Div.2-C【DP+思维】

本文探讨了两种解决特定字符选择问题的方法:爆搜(深度优先搜索)和动态规划。爆搜策略虽然在小规模数据下可行,但效率较低。动态规划方法试图通过状态转移来优化,但遇到了困难。最终,题解提供了一种巧妙的动态规划解决方案,通过维护每个位置最近的数字、小写字母和特殊符号的距离,避免了状态过多的问题,有效地找到了最小移动步数。

Date:2022.01.01

题意:n行m列的字符,每行只能选一个,且选完n个后至少分别存在一个数字、小写字母、’*’ || ‘#’ || ‘&’。
在这里插入图片描述

思路①:n、m<=50,试试能不能爆搜。dfs参数里标记每个元素的数量和移动的总步骤,当每个元素的数量和种类都满足条件时记录答案并跳出,然而会t。【注意比较烦人的是有的元素可能倒着走更近,预处理一下就好】
在这里插入图片描述
代码如下:

#include <bits/stdc++.h>
using namespace std;
const int N = 55;
typedef long long LL;
LL t,n,m,k;
bool st[N];
char c[N][N];
LL minn=1e9;
void dfs(int u,int digit,int latin,int symbol,LL sum)
{
    if(digit+latin+symbol>n||(digit+latin+symbol)==n&&(digit==0||latin==0||symbol==0)) return;
    if(u==n+1)
    {
        if(digit>0&&latin>0&&symbol)
        {
            minn=min(sum,minn);
            return;
        }
        else return;
    }
        for(int j=1;j<=m;j++)
        {
            if(c[u][j]=='*'||c[u][j]=='#'||c[u][j]=='&')
            {
                dfs(u+1,digit,latin,symbol+1,sum+j-1);
            }
            else if(c[u][j]>='0'&&c[u][j]<='9')
            {
                dfs(u+1,digit+1,latin,symbol,sum+j-1);
            }
            else if(c[u][j]>='a'&&c[u][j]<='z')
            {
                dfs(u+1,digit,latin+1,symbol,sum+j-1);
            }
        }
        for(int j=m;j>=1;j--)
        {
            if(c[u][j]=='*'||c[u][j]=='#'||c[u][j]=='&')
            {
                dfs(u+1,digit,latin,symbol+1,sum+m-j+1);
            }
            else if(c[u][j]>='0'&&c[u][j]<='9')
            {
                dfs(u+1,digit+1,latin,symbol,sum+m-j+1);
            }
            else if(c[u][j]>='a'&&c[u][j]<='z')
            {
                dfs(u+1,digit,latin+1,symbol,sum+m-j+1);
            }
        }
}
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) cin>>c[i][j];
    dfs(1,0,0,0,0);
    cout<<minn;
    return 0;
}

思路②:dp。
让f[i][j][k]:前i行存在j个数字、k个字母,因此间接存在至多i-j-k个符号,接着写转移方程。【之所以没标注符号个数为第四维是怕re】
在这里插入图片描述然后就是半天转移不出来,后来一想这样dp存在问题,首先存在符号不足或超过i-j-k个的情况,这样根本无法转移;其次关于符号个数的初始状态无法确认,这样转移很难做。

思路③:看了题解,dp照常,用三个状态f[i][0]、f[i][1]、f[i][2]表示从第i行第1个开始最近的数字、小写字母、符号,该行中没有则为INF。求答案时,我们只需枚举三种不同的东西分别在哪一行,但不让他们彼此之间同行。因此只需满足其中三行分别包含三种,其他行的元素都在第一个不用移动,这样总移动距离一定是最小的,好妙%%%。
代码如下:

#include <bits/stdc++.h>
using namespace std;
const int N = 110;
typedef long long LL;
LL t,n,m,k;
char c[N][N];
LL f[N][4];
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>c[i][j];
    for(int i=0;i<N;i++)
        for(int j=0;j<=2;j++)
            f[i][j]=1e9;
    //for(int i=0;i<=2;i++)
        //f[0][i]=0;
    for(LL i=1;i<=n;i++)
    {
        for(LL j=1;j<=m;j++)
        {
            if((c[i][j]>='0'&&c[i][j]<='9'))
                f[i][0]=min(f[i][0],min(j-1,m-j+1));
            if((c[i][j]>='a'&&c[i][j]<='z'))
                f[i][1]=min(f[i][1],min(j-1,m-j+1));
            if((c[i][j]=='*'||c[i][j]=='#'||c[i][j]=='&')) 
                f[i][2]=min(f[i][2],min(j-1,m-j+1));
        }
    }
    LL minn=1e9;
    //枚举三个不同符号分别在哪行,其它行无需移动即可
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
        if(i!=j)
            for(int k=1;k<=n;k++)
            {
                if(i!=k&&j!=k)
                    minn=min(f[i][0]+f[j][1]+f[k][2],minn);
            }
        }
    }
    cout<<minn;
    return 0;
}
orangepi@orangepi3-lts:~$ gpio readall +------+-----+----------+--------+---+ OPi 3 +---+--------+----------+-----+------+ | GPIO | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | GPIO | +------+-----+----------+--------+---+----++----+---+--------+----------+-----+------+ | | | 3.3V | | | 1 || 2 | | | 5V | | | | 122 | 0 | SDA.0 | OFF | 0 | 3 || 4 | | | 5V | | | | 121 | 1 | SCL.0 | OFF | 0 | 5 || 6 | | | GND | | | | 118 | 2 | PWM.0 | OFF | 0 | 7 || 8 | 0 | OFF | PL02 | 3 | 354 | | | | GND | | | 9 || 10 | 0 | OFF | PL03 | 4 | 355 | | 120 | 5 | RXD.3 | OFF | 0 | 11 || 12 | 0 | OFF | PD18 | 6 | 114 | | 119 | 7 | TXD.3 | OFF | 0 | 13 || 14 | | | GND | | | | 362 | 8 | PL10 | OFF | 0 | 15 || 16 | 0 | OFF | PD15 | 9 | 111 | | | | 3.3V | | | 17 || 18 | 0 | OFF | PD16 | 10 | 112 | | 229 | 11 | MOSI.1 | OFF | 0 | 19 || 20 | | | GND | | | | 230 | 12 | MISO.1 | OFF | 0 | 21 || 22 | 0 | OFF | PD21 | 13 | 117 | | 228 | 14 | SCLK.1 | OFF | 0 | 23 || 24 | 0 | OFF | CE.1 | 15 | 227 | | | | GND | | | 25 || 26 | 0 | OFF | PL08 | 16 | 360 | +------+-----+----------+--------+---+----++----+---+--------+----------+-----+------+ | GPIO | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | GPIO | +------+-----+----------+--------+---+ OPi 3 +---+--------+----------+-----+------+ 接线说明 SPI接口连接: MOSI (Master Out Slave In): Orange Pi的PH5引脚连接到MCP2515的MOSI引脚。 MISO (Master In Slave Out): Orange Pi的PH6引脚连接到MCP2515的MISO引脚。 CLK (Clock): Orange Pi的PH4引脚连接到MCP2515的CLK引脚。 CS (Chip Select): Orange Pi的PH3引脚连接到MCP2515的CS(或称为SPI_CS)引脚。 中断引脚连接: INT (Interrupt): MCP2515的中断引脚连接到Orange Pi的PD21引脚。这个引脚用于MCP2515向Orange Pi发送中断信号,例如当接收到新的CAN消息时。 sudo vi /boot/orangepiEnv.txt打开以后 verbosity=1 bootlogo=false console=both disp_mode=1920x1080p60 overlay_prefix=sun50i-h6 rootdev=UUID=ec9348ec-5bc4-4cf0-bb58-e34cad311a94 rootfstype=ext4 overlays=spi-spidev1 usbstoragequirks=0x2537:0x1066:u,0x2537:0x1068:u orangepi@orangepi3-lts:~$ cd /boot/dtb dtb/ dtb-5.10.75-sun50iw6/ orangepi@orangepi3-lts:~$ cd /boot/dtb/allwinner/ orangepi@orangepi3-lts:/boot/dtb/allwinner$ ls overlay sun50i-h5-orangepi-one.dtb sun50i-h5-orangepi-pc.dtb sun50i-h5-orangepi-zero-plus2.dtb sun50i-h616-orangepi-zero2.dtb sun50i-h6-orangepi-3-lts.dtb sun50i-h6-orangepi-one-plus.dtb sun50i-a64-orangepi-win.dtb sun50i-h5-orangepi-pc2.dtb sun50i-h5-orangepi-prime.dtb sun50i-h5-orangepi-zero-plus.dtb sun50i-h6-orangepi-3.dtb sun50i-h6-orangepi-lite2.dtb orangepi@orangepi3-lts:/boot/dtb/allwinner$ cd overlay/ orangepi@orangepi3-lts:/boot/dtb/allwinner/overlay$ ls -a . sun50i-a64-i2c1.dtbo sun50i-a64-uart2.dtbo sun50i-h5-cpu-clock-1.0GHz-1.1v.dtbo sun50i-h5-i2c1.dtbo sun50i-h5-spi-jedec-nor.dtbo sun50i-h5-usbhost1.dtbo sun50i-h6-i2c1.dtbo sun50i-h6-spi-spidev1.dtbo .. sun50i-a64-pps-gpio.dtbo sun50i-a64-uart3.dtbo sun50i-h5-cpu-clock-1.2GHz-1.3v.dtbo sun50i-h5-i2c2.dtbo sun50i-h5-spi-spidev.dtbo sun50i-h5-usbhost2.dtbo sun50i-h6-i2c2.dtbo sun50i-h6-spi-spidev.dtbo README.sun50i-a64-overlays sun50i-a64-spi-add-cs1.dtbo sun50i-a64-uart4.dtbo sun50i-h5-cpu-clock-1.3GHz-1.3v.dtbo sun50i-h5-pps-gpio.dtbo sun50i-h5-uart1.dtbo sun50i-h5-usbhost3.dtbo sun50i-h6-pwm.dtbo sun50i-h6-uart1.dtbo README.sun50i-h5-overlays sun50i-a64-spi-jedec-nor.dtbo sun50i-a64-w1-gpio.dtbo sun50i-h5-fixup.scr sun50i-h5-pwm.dtbo sun50i-h5-uart2.dtbo sun50i-h5-w1-gpio.dtbo sun50i-h6-ruart.dtbo sun50i-h6-uart2.dtbo sun50i-a64-fixup.scr sun50i-a64-spi-spidev.dtbo sun50i-h5-analog-codec.dtbo sun50i-h5-gpio-regulator-1.3v.dtbo sun50i-h5-spdif-out.dtbo sun50i-h5-uart3.dtbo sun50i-h6-fixup.scr sun50i-h6-spi-add-cs1.dtbo sun50i-h6-uart3.dtbo sun50i-a64-i2c0.dtbo sun50i-a64-uart1.dtbo sun50i-h5-cir.dtbo sun50i-h5-i2c0.dtbo sun50i-h5-spi-add-cs1.dtbo sun50i-h5-usbhost0.dtbo sun50i-h6-i2c0.dtbo sun50i-h6-spi-jedec-nor.dtbo sun50i-h6-w1-gpio.dtbo orangepi@orangepi3-lts:/boot/dtb/allwinner/overlay$ 配置不成功
06-13
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值