区间DP

来源:互联网 发布:mac电子相册制作软件 编辑:程序博客网 时间:2024/05/23 15:39

                                                        区间dp

一、题目链接

Brackets
Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 4946 Accepted: 2652

Description

We give the following inductive definition of a “regular brackets” sequence:

  • the empty sequence is a regular brackets sequence,
  • if s is a regular brackets sequence, then (s) and [s] are regular brackets sequences, and
  • if a and b are regular brackets sequences, then ab is a regular brackets sequence.
  • no other sequence is a regular brackets sequence

For instance, all of the following character sequences are regular brackets sequences:

(), [], (()), ()[], ()[()]

while the following character sequences are not:

(, ], )(, ([)], ([(]

Given a brackets sequence of characters a1a2 … an, your goal is to find the length of the longest regular brackets sequence that is a subsequence of s. That is, you wish to find the largest m such that for indices i1i2, …, imwhere 1 ≤ i1 < i2 < … < im ≤ nai1ai2 … aim is a regular brackets sequence.

Given the initial sequence ([([]])], the longest regular brackets subsequence is [([])].

Input

The input test file will contain multiple test cases. Each input test case consists of a single line containing only the characters ()[, and ]; each input test will have length between 1 and 100, inclusive. The end-of-file is marked by a line containing the word “end” and should not be processed.

Output

For each input case, the program should print the length of the longest possible regular brackets subsequence on a single line.

Sample Input

((()))()()()([]]))[)(([][][)end

Sample Output

66406

Source

Stanford Local 2004

题意:求匹配括号的个数。

题解:

三步骤:1.写判断满足题意的函数;2.数据初始化;3.区间dp的更新。

   关于dp更新:1.[ i,j ]的区间中,设j为新加入的点,若 i,j 匹配,则dp[i][j]=dp[i+1][j-1]+2.   除此之外,还有持续地下一步更新,把区间以k+1分为两段,设k+1与j匹配,则有dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]);

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. #include<cstdio>  
  2. #include<cstring>  
  3. #include<iostream>  
  4. #include<algorithm>  
  5. #include<cmath>  
  6. #include<queue>  
  7. #include<cstdlib>  
  8. #include<string>  
  9. using namespace std;  
  10.   
  11. #define N 110  
  12.   
  13. char str[N];  
  14. int dp[N][N];  
  15. bool check(int i,int j)  
  16. {  
  17.     if(str[i]=='['&&str[j]==']'return true;  
  18.     if(str[i]=='('&&str[j]==')'return true;  
  19.     return false;  
  20. }  
  21.   
  22. int main()  
  23. {  
  24.     while(~scanf("%s",str))  
  25.     {  
  26.         if(str[0]=='e')  
  27.             break;  
  28.         memset(dp,0,sizeof(dp));  
  29.         int l=strlen(str);  
  30.         for(int i=0;i<l-1;i++)  
  31.             if(check(i,i+1)) dp[i][i+1]=2;  
  32.         for(int n=3;n<=l;n++)  
  33.         {  
  34.             for(int i=0; i+n-1<l; i++)  
  35.             {  
  36.                 if(check(i,i+n-1)) dp[i][i+n-1]=dp[i+1][i+n-2]+2;  
  37.                 for(int j=i;j<i+n-1;j++)  
  38.                     dp[i][i+n-1]=max(dp[i][i+n-1],dp[i][j]+dp[j+1][i+n-1]);  
  39.             }  
  40.         }  
  41.         printf("%d\n",dp[0][l-1]);  
  42.     }  
  43.     return 0;  
  44. }  

二、记忆化搜索的方法。

整合在一起的代码是 d[i][j]=max(d[i+1]d[j],d[i+1][k-1]+d[k+1][j]+2);  i<k<=j; i和k匹配取后者,否之前者。

注意:不匹配的时候注意记得更新 d[i][j]=solve(i+1,j);

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. #include<cstdio>  
  2. #include<cstring>  
  3. #include<iostream>  
  4. #include<algorithm>  
  5. #include<cmath>  
  6. #include<queue>  
  7. #include<cstdlib>  
  8. #include<string>  
  9. using namespace std;  
  10.   
  11. #define N 110  
  12.   
  13. char str[N];  
  14. int dp[N][N];  
  15. bool check(int i,int j)  
  16. {  
  17.     if(str[i]=='['&&str[j]==']'return true;  
  18.     if(str[i]=='('&&str[j]==')'return true;  
  19.     return false;  
  20. }  
  21.   
  22. int solve(int i,int j)  
  23. {  
  24.     if(dp[i][j]>=0) return dp[i][j];  
  25.     if(j<=i)  return dp[i][j]=0;  
  26.     if(j==i+1)  
  27.     {  
  28.         if(check(i,j))  
  29.           return dp[i][j]=2;  
  30.         else  
  31.           return  dp[i][j]=0;  
  32.     }  
  33.     dp[i][j]=solve(i+1,j);     //不满足匹配的条件时的值。  
  34.     for(int k=i+1;k<=j;k++)  
  35.     {  
  36.         if(check(i,k))  
  37.             dp[i][j]=max(dp[i][j],solve(i+1,k-1)+solve(k+1,j)+2);  
  38.     }  
  39.      return dp[i][j];  
  40. }  
  41.   
  42. int main()  
  43. {  
  44.     while(~scanf("%s",str))  
  45.     {  
  46.         if(str[0]=='e')  
  47.             break;  
  48.         memset(dp,-1,sizeof(dp));  
  49.         int l=strlen(str);  
  50.         printf("%d\n",solve(0,l-1));  
  51.     }  
  52.     return 0;  
  53. }  



二、想看题目?戳我呀

Language:
Multiplication Puzzle
Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 8012 Accepted: 4958

Description

The multiplication puzzle is played with a row of cards, each containing a single positive integer. During the move player takes one card out of the row and scores the number of points equal to the product of the number on the card taken and the numbers on the cards on the left and on the right of it. It is not allowed to take out the first and the last card in the row. After the final move, only two cards are left in the row. 

The goal is to take cards in such order as to minimize the total number of scored points. 

For example, if cards in the row contain numbers 10 1 50 20 5, player might take a card with 1, then 20 and 50, scoring 
10*1*50 + 50*20*5 + 10*50*5 = 500+5000+2500 = 8000

If he would take the cards in the opposite order, i.e. 50, then 20, then 1, the score would be 
1*50*20 + 1*20*5 + 10*1*5 = 1000+100+50 = 1150.

Input

The first line of the input contains the number of cards N (3 <= N <= 100). The second line contains N integers in the range from 1 to 100, separated by spaces.

Output

Output must contain a single integer - the minimal score.

Sample Input

610 1 50 50 20 5

Sample Output

3650

Source

Northeastern Europe 2001, Far-Eastern Subregion

题意:问取出一段数字除首尾外的所有数字的最小消费是多少,取出每个数字的消费是 该数字与左右两端数字的乘积。


题解:运用区间dp的方法。枚举区间[i,j]中 i+1 到j-1 中的每个值,看最小消费是多少。

dp[i,j]=min(dp[i][j],dp[i][k]+dp[k][j]+num[i]*num[k]*num[j]); i<k<j;

注意初始化,动态规划中的初始化需要特别重视,初始化出现错误,结果就会错。

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. #include<cstdio>  
  2. #include<cstring>  
  3. #include<iostream>  
  4. #include<algorithm>  
  5. #include<cmath>  
  6. #include<queue>  
  7. #include<cstdlib>  
  8. #include<string>  
  9. using namespace std;  
  10.   
  11. #define N 105  
  12. #define inf 99999999  
  13.   
  14. int num[N];  
  15. int dp[N][N];  
  16.   
  17. int main()  
  18. {  
  19.     int n;  
  20.     while(~scanf("%d",&n))  
  21.     {  
  22.         for(int i=1;i<=n;i++)  
  23.             scanf("%d",&num[i]);  
  24.         for(int i=0;i<=N;i++)  
  25.             for(int j=0;j<=N;j++)  
  26.               dp[i][j]=inf;  
  27.         for(int i=1;i<n;i++)  
  28.         {  
  29.             dp[i][i+2]=num[i]*num[i+1]*num[i+2];  
  30.             dp[i][i]=dp[i][i+1]=0;  
  31.         }  
  32.   
  33.         for(int k=4;k<=n;k++)  
  34.         {  
  35.              for(int i=1;i+k-1<=n;i++)  
  36.              {  
  37.                  for(int j=i+1;j<i+k-1;j++)  
  38.                     dp[i][i+k-1]=min(dp[i][i+k-1],dp[i][j]+dp[j][i+k-1]+num[i]*num[i+k-1]*num[j]);  
  39.              }  
  40.         }  
  41.         printf("%d\n",dp[1][n]);  
  42.     }  
  43.     return 0;  
  44. }  

三、想看题目?戳我呀

Language:
Cheapest Palindrome
Time Limit: 2000MS Memory Limit: 65536KTotal Submissions: 7449 Accepted: 3601

Description

Keeping track of all the cows can be a tricky task so Farmer John has installed a system to automate it. He has installed on each cow an electronic ID tag that the system will read as the cows pass by a scanner. Each ID tag's contents are currently a single string with length M (1 ≤ M ≤ 2,000) characters drawn from an alphabet of N (1 ≤ N ≤ 26) different symbols (namely, the lower-case roman alphabet).

Cows, being the mischievous creatures they are, sometimes try to spoof the system by walking backwards. While a cow whose ID is "abcba" would read the same no matter which direction the she walks, a cow with the ID "abcb" can potentially register as two different IDs ("abcb" and "bcba").

FJ would like to change the cows's ID tags so they read the same no matter which direction the cow walks by. For example, "abcb" can be changed by adding "a" at the end to form "abcba" so that the ID is palindromic (reads the same forwards and backwards). Some other ways to change the ID to be palindromic are include adding the three letters "bcb" to the begining to yield the ID "bcbabcb" or removing the letter "a" to yield the ID "bcb". One can add or remove characters at any location in the string yielding a string longer or shorter than the original string.

Unfortunately as the ID tags are electronic, each character insertion or deletion has a cost (0 ≤ cost ≤ 10,000) which varies depending on exactly which character value to be added or deleted. Given the content of a cow's ID tag and the cost of inserting or deleting each of the alphabet's characters, find the minimum cost to change the ID tag so it satisfies FJ's requirements. An empty ID tag is considered to satisfy the requirements of reading the same forward and backward. Only letters with associated costs can be added to a string.

Input

Line 1: Two space-separated integers: N and M 
Line 2: This line contains exactly M characters which constitute the initial ID string 
Lines 3..N+2: Each line contains three space-separated entities: a character of the input alphabet and two integers which are respectively the cost of adding and deleting that character.

Output

Line 1: A single line with a single integer that is the minimum cost to change the given name tag.

Sample Input

3 4abcba 1000 1100b 350 700c 200 800

Sample Output

900

Hint

If we insert an "a" on the end to get "abcba", the cost would be 1000. If we delete the "a" on the beginning to get "bcb", the cost would be 1100. If we insert "bcb" at the begining of the string, the cost would be 350 + 200 + 350 = 900, which is the minimum.

Source

USACO 2007 Open Gold

题意:问 让给出的的字符串变为回文串的最小花费是多少

题解:首先有一个小tip,对于增删字母的花费,我们每次只会选择最小的花费,所以增删的费用中,我们只需保存最小的在add[i]。我们设dp[i][j]表示字符串从i到j变为回文串的最小花费。

然后有3种情况:1.s[i]=s[j],dp[i][j]=dp[i+1][j-1];

          2.如果dp[i+1][j]是(变为)回文串(的消费),则dp[i][j]=dp[i+1][j]+add[i];

          3.如果dp[i][j-1]是(变为)回文串(的消费),则dp[i][j]=dp[i][j-1]+add[j];

注:dp后都能变为回文串。再次强调,dp中初始化很重要。
[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. #include<cstdio>  
  2. #include<cstring>  
  3. #include<iostream>  
  4. #include<algorithm>  
  5. #include<cmath>  
  6. #include<queue>  
  7. #include<cstdlib>  
  8. #include<string>  
  9. using namespace std;  
  10.   
  11. #define N 2010  
  12. #define inf 0x3f3f3f3f  
  13.   
  14. int m,n,ad,de;  
  15. int add[30];  
  16. int s[N];  
  17. int dp[N][N];  
  18.   
  19. int main()  
  20. {  
  21.     while(~scanf("%d%d",&n,&m))  
  22.     {  
  23.         char ch;  
  24.         char c[2];  
  25.         memset(s,-1,sizeof(s));  
  26.         for(int i=0;i<m;i++)  
  27.         {  
  28.             cin>>ch;  
  29.             s[i]=ch-'a';  
  30.         }  
  31.         for(int i=0;i<n;i++)  
  32.         {  
  33.             cin>>c;  
  34.             int cc=c[0]-'a';  
  35.             cin>>ad>>de;  
  36.             add[cc]=min(ad,de);  
  37.         }  
  38.         memset(dp,0,sizeof(dp));  
  39.         for(int k=1;k<m;k++)  
  40.         {  
  41.             for(int i=0,j=k;j<m;i++,j++)  
  42.             {  
  43.                 dp[i][j]=inf;  
  44.                 if(s[i]==s[j])  
  45.                     dp[i][j]=dp[i+1][j-1];  
  46.                 else  
  47.                 {  
  48.                     dp[i][j]=min(dp[i][j-1]+add[s[j]],dp[i][j]);  
  49.                     dp[i][j]=min(dp[i+1][j]+add[s[i]],dp[i][j]);  
  50.                 }  
  51.             }  
  52.         }  
  53.        printf("%d\n",dp[0][m-1]);  
  54.     }  
  55.     return 0;  
  56. }  

四、瞅啥呢?原题目链接在这里
Language:
Brackets Sequence
Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 28991 Accepted: 8247 Special Judge

Description

Let us define a regular brackets sequence in the following way: 

1. Empty sequence is a regular sequence. 
2. If S is a regular sequence, then (S) and [S] are both regular sequences. 
3. If A and B are regular sequences, then AB is a regular sequence. 

For example, all of the following sequences of characters are regular brackets sequences: 

(), [], (()), ([]), ()[], ()[()] 

And all of the following character sequences are not: 

(, [, ), )(, ([)], ([(] 

Some sequence of characters '(', ')', '[', and ']' is given. You are to find the shortest possible regular brackets sequence, that contains the given character sequence as a subsequence. Here, a string a1 a2 ... an is called a subsequence of the string b1 b2 ... bm, if there exist such indices 1 = i1 < i2 < ... < in = m, that aj = bij for all 1 = j = n.

Input

The input file contains at most 100 brackets (characters '(', ')', '[' and ']') that are situated on a single line without any other characters among them.

Output

Write to the output file a single line that contains some regular brackets sequence that has the minimal possible length and contains the given sequence as a subsequence.

Sample Input

([(]

Sample Output

()[()]

Source

Northeastern Europe 2001

题意:根据题目所给的字符串添加括号,输出最短的匹配括号串。(题目隐含给出的字符串包含空格,所以输入的时候必须用gets输入,scanf 是以回车和空格作为结束符号,gets只以回车作为结束)

题解:1.用结构体来保存(从 i 到 j 所需添加的最少括号的数目dp[ i ][ j ].t、添加括号后构成的新的括号串dp[ i ][ j ].s),string 可以字符串之间直接相加减。
            2.当s[i]==s[j] 时,dp[ i ][ j ].t=min(dp[ i ][ j ].t,dp[ i+1 ][ j -1].t) ,否则,从 i 到 j 之间枚举k,dp[ i ][ j ].t=dp[ i ][ k ].t+dp[ k+1 ][ j ].t .

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. #include<cstdio>  
  2. #include<cstring>  
  3. #include<iostream>  
  4. #include<algorithm>  
  5. #include<cmath>  
  6. #include<queue>  
  7. #include<cstdlib>  
  8. #include<string>  
  9. using namespace std;  
  10.   
  11. #define N 2010  
  12. #define inf 99999999  
  13.   
  14. struct node  
  15. {  
  16.     int t;  
  17.     string s;  
  18. }dp[110][110];  
  19.   
  20. char str[110];  
  21. string ss;  
  22.   
  23. void init(int l)  
  24. {  
  25.     for(int i=0; i<l; i++)  
  26.     {  
  27.         for(int j=i; j<l; j++)  
  28.         {  
  29.             dp[i][j].s="";  
  30.             dp[i][j].t=inf;  
  31.         }  
  32.     }  
  33.     for(int i=0; i<l; i++)  
  34.     {  
  35.         dp[i][i].t=1;  
  36.         if(ss[i]=='('||ss[i]==')')  
  37.             dp[i][i].s="()";  
  38.         else  
  39.             dp[i][i].s="[]";  
  40.     }  
  41. }  
  42. int main()  
  43. {  
  44.     while(gets(str))  
  45.     {  
  46.         ss=str;  
  47.         int l=ss.size();  
  48.         init(l);  
  49.   
  50.         for(int i=l-1; i>=0; i--)  
  51.         {  
  52.             for(int j=i+1; j<l; j++)  
  53.             {  
  54.                 if((ss[i]=='('&&ss[j]==')')||(ss[i]=='['&&ss[j]==']'))  
  55.                 {  
  56.                     if(dp[i][j].t > dp[i+1][j-1].t)  
  57.                     {  
  58.                      dp[i][j].t=dp[i+1][j-1].t;  
  59.                      dp[i][j].s=ss[i]+dp[i+1][j-1].s+ss[j];  
  60.                     }  
  61.   
  62.                 }  
  63.                 for(int k=i; k<j; k++)  
  64.                 {  
  65.                     if(dp[i][j].t > dp[i][k].t+dp[k+1][j].t)  
  66.                     {  
  67.                         dp[i][j].t=dp[i][k].t+dp[k+1][j].t;  
  68.                         dp[i][j].s=dp[i][k].s+dp[k+1][j].s;  
  69.                     }  
  70.                 }  
  71.             }  
  72.         }  
  73.         cout<<dp[0][l-1].s<<endl;  
  74.     }  
  75.     return 0;  
  76. }  


五、听说点开这里可以看见奇迹
Language:
Running
Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 5853 Accepted: 2198

Description

The cows are trying to become better athletes, so Bessie is running on a track for exactly N (1 ≤ N ≤ 10,000) minutes. During each minute, she can choose to either run or rest for the whole minute.

The ultimate distance Bessie runs, though, depends on her 'exhaustion factor', which starts at 0. When she chooses to run in minute i, she will run exactly a distance of Di (1 ≤ Di ≤ 1,000) and her exhaustion factor will increase by 1 -- but must never be allowed to exceed M (1 ≤ M ≤ 500). If she chooses to rest, her exhaustion factor will decrease by 1 for each minute she rests. She cannot commence running again until her exhaustion factor reaches 0. At that point, she can choose to run or rest.

At the end of the N minute workout, Bessie's exaustion factor must be exactly 0, or she will not have enough energy left for the rest of the day.

Find the maximal distance Bessie can run.

Input

* Line 1: Two space-separated integers: N and M
* Lines 2..N+1: Line i+1 contains the single integer: Di

Output

* Line 1: A single integer representing the largest distance Bessie can run while satisfying the conditions.
 

Sample Input

5 2534210

Sample Output

9

Source

USACO 2008 January Silver


题意:求在给出的n分钟内,跑的最远距离。num[ i ] 表示第i 分钟跑步的距离,m表示最大的疲劳值,每跑一分钟,疲劳值+1,每休息一分钟,疲劳值-1,不过一开始休息后,必须休息到疲劳值为0的时候,才能重新开始跑步,疲劳值为0 的时候也可以继续休息。

题解:用dp[ i ][ j ] 表示第i分钟疲劳值为j时跑的最大距离。则dp[ i ][ 0 ]有两种方式可以达到,1.疲劳值为0仍继续休息
dp[i][0]=dp[i-1][0];    2.第i-k分钟的疲劳值为k,然后休息k分钟后有 dp[ i ][ 0 ]=dp[ i-k ][ k ];         跑步时的距离dp[ i ][ j ]=dp[ i-1 ][ j-1 ]+num[ i ] ;

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. #include<cstdio>  
  2. #include<cstring>  
  3. #include<iostream>  
  4. #include<algorithm>  
  5. #include<cmath>  
  6. #include<queue>  
  7. #include<cstdlib>  
  8. #include<string>  
  9. using namespace std;  
  10.   
  11. #define N 2010  
  12. #define inf 99999999  
  13.   
  14. int dp[10005][505];  
  15. int num[10005];  
  16.   
  17. int main()  
  18. {  
  19.     int n,m;  
  20.     while(~scanf("%d%d",&n,&m))  
  21.     {  
  22.         for(int i=1; i<=n; i++)  
  23.         {  
  24.             scanf("%d",&num[i]);  
  25.         }  
  26.   
  27.         memset(dp,0,sizeof(dp));  
  28.   
  29.         for(int i=1; i<=n; i++)  
  30.         {  
  31.             for(int j=1; j<=m; j++)           //初始化取值,任意时间任意疲劳数的初值,方便后面的调用。  
  32.             {  
  33.                 dp[i][j]=dp[i-1][j-1]+num[i];  
  34.             }  
  35.   
  36.             dp[i][0]=dp[i-1][0];             //两种情况的判定,疲劳数变为0的情况。  
  37.   
  38.             for(int k=1; k<=m; k++)  
  39.             {  
  40.                 if(i-k>0)  
  41.                     dp[i][0]=max(dp[i][0],dp[i-k][k]);   //保证最后的疲劳数为0的情况下,获得最大的值。  
  42.             }  
  43.         }  
  44.         printf("%d\n",dp[n][0]);  
  45.     }  
  46.     return 0;  
  47. }  
1 0
原创粉丝点击