洛谷题单指南-动态规划3-P4290 [HAOI2008] 玩具取名
原题链接:https://www.luogu.com.cn/problem/P4290
题意解读:W、I、N、G中一个字母可以替换为多种两个字母,给定目标串,求能从W、I、N、G中哪些单个字母变形得到。
解题思路:
1、状态表示:
设W、I、N、G为1、2、3、4,函数int getnum(char c)用于将字符转换为对应整数,
设ok[i][j][k]=1表示ij可以由k变形而来,ijk是1、2、3、4,代表W、I、N、G,
设dp[i][j][z]表示i~j的字符串能否从k(取值1-4)变形而来,值为1或0,
设目标字符串为s。
2、状态转移
枚举i~j之间的分界点k,再枚举xyz(取值1-4),如果dp[i][k][x] && dp[k+1][j][y] && ok[x][y][z],说明dp[i][j][z] = 1
3、初始化:
根据输入数据填充ok[][][]
dp[i][i][getnum(s[i])] = 1,表示一个字符可以从自身变形过来。
4、结果
如果dp[1][n][1] = 1,输出'W'
如果dp[1][n][2] = 1,输出'I'
如果dp[1][n][3] = 1,输出'N'
如果dp[1][n][4] = 1,输出'G'
100分代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 205;
int cnt[5];
string s;
bool ok[5][5][5];
bool dp[N][N][5];
int getnum(char c)
{
if(c == 'W') return 1;
if(c == 'I') return 2;
if(c == 'N') return 3;
if(c == 'G') return 4;
}
int main()
{
cin >> cnt[1] >> cnt[2] >> cnt[3] >> cnt[4];
char l, r;
for(int i = 1; i <= 4; i++)
{
for(int j = 1; j <= cnt[i]; j++)
{
cin >> l >> r;
ok[getnum(l)][getnum(r)][i] = 1;
}
}
cin >> s;
int n = s.size();
s = " " + s; //字符串从1开始
for(int len = 1; len <= n; len++) //枚举区间长度
{
for(int i = 1; i + len - 1 <= n; i++) //枚举左端点
{
int j = i + len - 1; //计算右端点
if(len == 1)
{
dp[i][j][getnum(s[i])] = 1;
}
else
{
for(int k = i; k < j; k++) //枚举分界点
{
for(int x = 1; x <= 4; x++)
{
for(int y = 1; y <= 4; y++)
{
for(int z = 1; z <= 4; z++)
{
if(dp[i][k][x] && dp[k+1][j][y] && ok[x][y][z])
{
dp[i][j][z] = 1;
}
}
}
}
}
}
}
}
bool yes = false;
if(dp[1][n][1]) yes = true, cout << "W";
if(dp[1][n][2]) yes = true, cout << "I";
if(dp[1][n][3]) yes = true, cout << "N";
if(dp[1][n][4]) yes = true, cout << "G";
if(!yes) cout << "The name is wrong!";
return 0;
}