今日遇到一个很适合用来学习动态规划的题目,记录一下做法。
题目:有一个词典,词典中有单词,每个单词有一个权重。输入一个字符串,将字符串根据词典划分为一个个“单词”,对应的权重为每个单词的权重和。如词典中:abcdefg,根据词典划分,/abc/de/fg,权重为abc、de和fg的权重之和。要求输出权重最大的一种分割结果。
(这里我将词典写到代码中,也可以自己构建。)输入是一串字符串。
分析:dp[i]表示前i个字符的最大权重和。
dp[0]=0,dp[i]=max(dp[j-1]+(j-1到i的子字符串权重)),其中j从1到i,i从1到n。
#include <stdio.h>
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
using namespace std;
// 定义词典,每个单词对应一个权重
unordered_map<string, int> dictionary = {
{"a", 3},
{"b",2},
{"bos", 2},
{"os",4},
{"s",10},
//{"bo",1}
// 添加其他单词和权重
};
// 计算字符串的权重
int calculateWeight(const string& str) {
if (dictionary.find(str) != dictionary.end()) {
return dictionary[str];
}
return 0; // 如果词典中没有对应单词,则权重为0
}
// 动态规划函数,返回权重最大的分割方法
string maximizeWeight(const string& input) {
int n = input.length();//输入单词长度
vector<int> dp(n + 1, 0); // dp[i]表示前i个字符的最大权重和
vector<string> result(n + 1, "");//对应位置存放分割的子字符串
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) {
if(dp[j-1]==-1) {
continue;//前j-1个字符串中有找不到的,那就跳过
}
string word = input.substr(j - 1, i - (j - 1));//从j-1到i的子字符串
int currentWeight = calculateWeight(word);
//更新dp[i]
if (currentWeight > 0 && dp[j-1] + currentWeight > dp[i]) {
dp[i] = dp[j-1] + currentWeight;
result[i] = word;
}
}
if(dp[i]==0)dp[i]=-1;//如果子字符串中一直有找不到的单词,dp为-1
}
for(auto dp:dp)cout<<dp<<",";
if(dp[n] == -1)return "-1";
// 从结果中回溯以找到最大权重和的分割方法
string segmentedInput;
int currentIndex = n;
while (currentIndex > 0) {
segmentedInput = result[currentIndex] + "\\" + segmentedInput;
currentIndex -= result[currentIndex].length();
}
return "\\"+segmentedInput;
}
int main() {
string input;
cout << "请输入字符串: ";
cin >> input;
string segmentedString = maximizeWeight(input);
cout << "权重最大的分割方法为: " << segmentedString << endl;
return 0;
}
结果: