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;
}


代码如下: