wenbao与dp

dp--一种非常神奇的算法

cf的一道C题,非常经典(弱鸡没有做出来)

http://codeforces.com/contest/711/problem/C

这是一道三维dp,题目意思是有m种颜料,给n颗树中为0的染色目的是相邻的不同的个数为k,输出最小的颜料

好难!!!!!!!!!!!!!!

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long 
 4 const ll maxn = 1e18+10;
 5 ll a[120], b[120][120],dp[120][120][120], sum = maxn;
 6 int main(){
 7     int n, m, k;
 8     cin>>n>>m>>k;
 9     for(int i = 1; i <= n; i++){
10         cin>>a[i];
11     }
12     for(int i = 1; i <= n; i++){
13         for(int j = 1; j <= m; j++)
14             cin>>b[i][j];
15     }
16     for(int i = 1; i <= n; i++){
17         for(int j = 1; j <= m; j++){
18             for(int k = 0; k <= n; k++){ //神奇 k=1;
19                 dp[i][j][k] = maxn;
20             }
21         }
22     }
23     // dp[0][0][0] = 0;
24     for(int i = 1; i <= n; i++){
25         for(int j = 1; j <= i; j++){
26             if(a[i]){
27                 dp[i][a[i]][j] = dp[i-1][a[i]][j];
28                 for(int k = 1; k <= m; k++){
29                     if(a[i]!=k)
30                     dp[i][a[i]][j] = min(dp[i][a[i]][j], dp[i-1][k][j-1]);
31                 }
32             }
33             else{
34                 for(int x = 1; x <= m; x++){
35                     for(int y = 1; y <= m; y++){
36                         if(x == y) dp[i][y][j] = min(dp[i][y][j],dp[i-1][x][j]+b[i][y]);
37                         else dp[i][y][j] = min(dp[i][y][j], dp[i-1][x][j-1]+b[i][y]);
38                     }
39                 }
40             }
41         }
42     }
43     for(int i = 1; i <= m; i++){
44         // cout<<dp[n][i][k]<<endl;
45         sum = min(sum,dp[n][i][k]);
46     }
47     cout<<(sum >= maxn ? -1: sum)<<endl;
48 }

hdu 2577

http://acm.split.hdu.edu.cn/showproblem.php?pid=2577

非常经典的dp,,shift 和 caps lock 输入大小写

神奇!!!!!!!!!!!!!! 

 1 #include <iostream>
 2 #include <string>
 3 using namespace std;
 4 int dp[120][3];
 5 int main(){
 6     int n, num;
 7     string str;
 8     cin>>n;
 9     while(n--){
10         num = 0;
11         cin>>str;
12         int len = str.length();
13         dp[0][0] = 0;
14         dp[0][1] = 1;
15         for(int i = 0; i < len; i++){
16             if(islower(str[i])){
17                 dp[i+1][0]=min(dp[i][0]+1, dp[i][1]+2);
18                 dp[i+1][1]=min(dp[i][0]+2, dp[i][1]+2);
19             }
20             else{
21                 dp[i+1][0]=min(dp[i][0]+2, dp[i][1]+2);
22                 dp[i+1][1]=min(dp[i][0]+2, dp[i][1]+1);
23             }
24         }
25         cout<<min(dp[len][1]+1, dp[len][0])<<endl;
26     }
27 }

dp的神奇在于每个数组的下标都表示某种特殊的状态,用来描述事物而不是单纯的数组,重点是找到前后的关系即动态转移方程

dp的特点是反复操作每次操作的步骤和结果都是固定的。。。。

只有不断学习才能进步!

原文地址:https://www.cnblogs.com/wenbao/p/5823484.html