动态规划

#algorithm/动态规划

01背包问题

有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。 第 i 件物品的体积是 vi,价值是 wi。 求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。 输出最大价值。

输入格式

第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。 接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值。

输出格式

输出一个整数,表示最大价值。

数据范围

0 < N, V ≤ 1000 
0 < vi, wi ≤ 1000

输入样例

4 5 1 2 2 4 3 4 4 5 

输出样例:

8

Source Code

#include <iostream>  
#include <vector>
#include <string>
#define int long long
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
using namespace std;
const int N = 1e6 + 10;
const int M = 1e3 + 10;
int n, m, t;
int v[M], w[M];
int f[M][M];

void solve() {
   cin >> n >> m;
   for(int i = 1; i <= n; i ++){
       cin >> v[i] >> w[i];
  }
   
   for(int i = 1; i <= n; i++){
       for(int j = 0; j <= m; j++){
           f[i][j] = f[i - 1][j];
           if(j >= v[i])f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i]);
      }
  }
   cout << f[n][m] << '\n';
}

signed main()
{
   IOS;
   int T = 1;
//   cin >> T;
   while(T--)solve();
   return 0;
}
#include <iostream>  
#include <algorithm>
using namespace std;
const int M = 1e6 + 10;
const int N = 1e3 + 10;
int n, m;

int main(){
   cin >> n >> m;
   int wt[N], val[N];
   int dp[N][N];
   
   for(int i = 0; i < N; i++){
       cin >> wt[i] >> val[i];
  }
   
   
   for(int i = 1; i <= n; i++){
       for(int j = 1; j <= m; j++){
           if(j - wt[i - 1] < 0){
               dp[i][j] = dp[i - 1][j];
          }else {
               dp[i][j] = max(
                   //放
                   dp[i - 1][j - wt[i - 1]] + val[i - 1],
                   //不放
                   dp[i - 1][j]
              );
          }
      }
  }
   
   // 输出结果
   cout << dp[n][m];
}
#include <iostream>  
#include <vector>
#include <string>
#define int long long
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
using namespace std;
const int N = 1e6 + 10;
const int M = 1e3 + 10;
int n, m, t;
int v[M], w[M];
int f[M];

void solve() {
   cin >> n >> m;
   for(int i = 1; i <= n; i ++){
       cin >> v[i] >> w[i];
  }
   
   for(int i = 1; i <= n; i++){
       for(int j = m; j >= v[i]; j--){
           f[j] = max(f[j], f[j - v[i]] + w[i]);
      }
  }
   cout << f[m] << '\n';
}

signed main()
{
   IOS;
   int T = 1;
//   cin >> T;
   while(T--)solve();
   return 0;
}

翻硬币

题目描述

小明正在玩一个”翻硬币”的游戏。 桌上放着排成一排的若干硬币。我们用 * 表示正面,用 o 表示反面(是小写字母,不是零)。 比如,可能情形是:oooooo; 如果同时翻转左边的两个硬币,则变为:oooo**oooo。 现在小明的问题是:如果已知了初始状态和要达到的目标状态,每次只能同时翻转相邻的两个硬币,那么对特定的局面,最少要翻动多少次呢? 我们约定:把翻动相邻的两个硬币叫做一步操作。

输入描述

两行等长的字符串,分别表示初始状态和要达到的目标状态。 每行的长度<1000。

输出描述

一个整数,表示最小操作步数。

输入输出样例

示例

输入

**********  
o****o****

输出

5

Source Code

#include <iostream>  
#include <vector>
#include <string>
#include <algorithm>
#define int long long
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
using namespace std;
const int N = 1e6 + 10;
const int M = 1e3 + 10;
int n, m, t;
string s1, s;

void check(int i){
   if(s[i] == '*')s[i] = 'o';
   else s[i] = '*';
}

void solve() {
   getline(cin, s);
   getline(cin, s1);
   int sum = 0;
   for(int i = 0; i < s.size(); i++){
       if(s[i] != s1[i]){
           check(i);
           check(i + 1);
           sum ++;
      }
  }
   cout << sum;
}

signed main()
{
   IOS;
   int T = 1;
   //   cin >> T;
   while(T--)solve();
   return 0;
}

题目描述

给定一个单词,请问在单词中删除 t 个字母后,能得到的字典序最小的单词是什么?

输入描述

输入的第一行包含一个单词,由大写英文字母组成。 第二行包含一个正整数 t_。 其中,单词长度不超过 100,_t 小于单词长度。

输出描述

输出一个单词,表示答案。

输入输出样例

示例 1

输入

LANQIAO   
3

输出

AIAO

Source Code

/*  
这段代码的功能是:给定一个字符串和一个整数k,每次可以删除一个字符,删除k次后得到一个新的字符串,要求新的字符串字典序最小。
代码的实现思路是:将字符串中的每个字符转换为数字,然后每次找到当前位置到当前位置+k之间的最小值,将其加入新的数组中,并将k减去当前位置到最小值位置的距离,直到k为0或者到达字符串结尾。
最后将新的数组中的数字转换为字符输出即可。
*/
#include <iostream>
#include <string>
using namespace std;

int main() {
   string s;
   getline(cin, s);
   int size;
   cin >> size;
   int ch[s.length()], arr[s.length() - size];
   int count = 0, a = 0, flag = a;
   for (int i = 0; i < s.length(); i++) {
       ch[i] = s[i] - 'A';
  }
   while (size > 0) {
       flag = a;
       for (int i = a; i <= flag + size; i++) {
           if (ch[a] > ch[i]) {
               a = i;
          }
      }
       size -= (a - flag);
       arr[count++] = ch[a];
       a++;
  }
   for (int i = a; i < s.length(); i++) {
       arr[count++] = ch[i];
  }
   for (int i = 0; i < count; i++) {
       cout << (char)(arr[i] + 'A');
  }
   return 0;
}

2834. 找出美丽数组的最小和

给你两个正整数:n 和 target 。

如果数组 nums 满足下述条件,则称其为 美丽数组 。

  • nums.length == n.
  • nums 由两两互不相同的正整数组成。
  • 在范围 [0, n-1] 内,不存在 两个 不同 下标 i 和 j ,使得 nums[i] + nums[j] == target 。

返回符合条件的美丽数组所可能具备的 最小 和,并对结果进行取模 109 + 7

示例 1:

输入:n = 2, target = 3
输出:4
解释:nums = [1,3] 是美丽数组。
- nums 的长度为 n = 2
- nums 由两两互不相同的正整数组成。
- 不存在两个不同下标 i 和 j ,使得 nums[i] + nums[j] == 3
可以证明 4 是符合条件的美丽数组所可能具备的最小和。

示例 2:

输入:n = 3, target = 3
输出:8
解释:
nums = [1,3,4] 是美丽数组。
- nums 的长度为 n = 3
- nums 由两两互不相同的正整数组成。
- 不存在两个不同下标 i 和 j ,使得 nums[i] + nums[j] == 3
可以证明 8 是符合条件的美丽数组所可能具备的最小和。

示例 3:

**输入:**n = 1, target = 1
**输出:**1
**解释:**nums = [1] 是美丽数组。

提示:

  • 1 <= n <= 109
  • 1 <= target <= 109