动态规划2
1、树形DP
2、概率DP
3、区间DP
模板
1 for (int len = 1; len < n; len++) { //操作区间的长度 2 for (int i = 0, j = len; j <= n; i++, j++) { //始末 3 //检查是否匹配(非必须) 4 for (int s = i; s < j; s++) { 5 //update 6 } 7 } 8 }
石子归并
1 #include <cstdio> 2 #define min(x, y) (x > y ? y : x) 3 #define INF 0x3f3f3f3f 4 using namespace std; 5 6 const int maxn = 210; 7 int dp[maxn][maxn]; 8 int sum[maxn]; 9 int a[maxn]; 10 11 int main(int argc, const char * argv[]) { 12 13 int n; 14 while (~scanf("%d", &n)) { 15 for (int i = 1; i <= n; i++) { 16 scanf("%d", &a[i]); 17 sum[i] = sum[i - 1] + a[i]; 18 } 19 for (int len = 1; len < n; len++) { //操作区间的长度 20 for (int i = 1, j = len + 1; j <= n; i++, j++) { //始末 21 //检查是否匹配(非必须) 22 dp[i][j] = INF; 23 for (int s = i; s < j; s++) { 24 dp[i][j] = min(dp[i][j], dp[i][s] + dp[s + 1][j] + sum[j] - sum[i - 1]); 25 } 26 } 27 } 28 printf("%d ", dp[1][n]); 29 } 30 return 0; 31 }
4、状态DP
练习题
E - Bag of mice
The dragon and the princess are arguing about what to do on the New Year's Eve. The dragon suggests flying to the mountains to watch fairies dancing in the moonlight, while the princess thinks they should just go to bed early. They are desperate to come to an amicable agreement, so they decide to leave this up to chance.
They take turns drawing a mouse from a bag which initially contains w white and b black mice. The person who is the first to draw a white mouse wins. After each mouse drawn by the dragon the rest of mice in the bag panic, and one of them jumps out of the bag itself (the princess draws her mice carefully and doesn't scare other mice). Princess draws first. What is the probability of the princess winning?
If there are no more mice in the bag and nobody has drawn a white mouse, the dragon wins. Mice which jump out of the bag themselves are not considered to be drawn (do not define the winner). Once a mouse has left the bag, it never returns to it. Every mouse is drawn from the bag with the same probability as every other one, and every mouse jumps out of the bag with the same probability as every other one.
Input
The only line of input data contains two integers w and b (0 ≤ w, b ≤ 1000).
OutputOutput the probability of the princess winning. The answer is considered to be correct if its absolute or relative error does not exceed 10 - 9.
Examples1 3
0.500000000
5 5
0.658730159
Let's go through the first sample. The probability of the princess drawing a white mouse on her first turn and winning right away is 1/4. The probability of the dragon drawing a black mouse and not winning on his first turn is 3/4 * 2/3 = 1/2. After this there are two mice left in the bag — one black and one white; one of them jumps out, and the other is drawn by the princess on her second turn. If the princess' mouse is white, she wins (probability is 1/2 * 1/2 = 1/4), otherwise nobody gets the white mouse, so according to the rule the dragon wins.
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <algorithm> 5 6 using namespace std; 7 8 const int maxn = 1100; 9 double dp[maxn][maxn]; 10 11 int main() 12 { 13 int w,b; 14 scanf("%d %d",&w,&b); 15 memset(dp,0,sizeof dp); 16 for(int i=0;i<=b;i++) 17 dp[0][i]=0; 18 for(int i=1;i<=w;i++) 19 dp[i][0]=1; 20 for(int i=1;i<=w;i++) 21 { 22 for(int j=1;j<=b;j++) 23 { 24 dp[i][j]+=(double)i/(i+j); 25 if(j>=3) 26 { 27 dp[i][j]+=(double)j/(j+i)*((double)(j-1)/(i+j-1))*((double)(j-2)/(i+j-2))*dp[i][j-3]; 28 } 29 if(j>=2) 30 { 31 dp[i][j]+=((double)j/(j+i))*((double)(j-1)/(i+j-1))*((double)(i)/(i+j-2))*dp[i-1][j-2]; 32 } 33 } 34 } 35 printf("%.9lf ",dp[w][b]); 36 return 0; 37 }
F - Brackets
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 i1, i2, …, im where 1 ≤ i1 < i2 < … < im ≤ n, ai1ai2 … aim is a regular brackets sequence.
Given the initial sequence ([([]])]
, the longest regular brackets subsequence is [([])]
.
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.
For each input case, the program should print the length of the longest possible regular brackets subsequence on a single line.
((())) ()()() ([]]) )[)( ([][][) endSample Output
6 6 4 0 6
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <algorithm> 5 #define INF 0x3f3f3f3f 6 7 using namespace std; 8 9 const int maxn = 110; 10 int dp[maxn][maxn]; 11 int sum[maxn]; 12 int a[maxn]; 13 14 15 int main() 16 { 17 char s[110]; 18 while(~scanf("%s",&s) && strcmp("end",s)!=0) 19 { 20 int s1=strlen(s); 21 memset(dp,0,sizeof(dp)); 22 for(int i=0;i<s1;i++) 23 dp[i][i]=1; 24 for(int l=1;l<s1;l++) 25 { 26 for(int i=0;i<s1-l;i++) 27 { 28 int j=i+l; 29 dp[i][j]=INF; 30 if((s[i]=='('&&s[j]==')') ||(s[i]=='['&&s[j]==']')) 31 { 32 dp[i][j]=dp[i+1][j-1]; 33 } 34 for(int k=i;k<j;k++) 35 { 36 dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]); 37 } 38 39 } 40 } 41 printf("%d ",s1-dp[0][s1-1]); 42 43 } 44 return 0; 45 }
G - Football
Consider a single-elimination football tournament involving 2n teams, denoted 1, 2, …, 2n. In each round of the tournament, all teams still in the tournament are placed in a list in order of increasing index. Then, the first team in the list plays the second team, the third team plays the fourth team, etc. The winners of these matches advance to the next round, and the losers are eliminated. After n rounds, only one team remains undefeated; this team is declared the winner.
Given a matrix P = [pij] such that pij is the probability that team i will beat team j in a match determine which team is most likely to win the tournament.
The input test file will contain multiple test cases. Each test case will begin with a single line containing n (1 ≤ n ≤ 7). The next 2n lines each contain 2n values; here, the jth value on the ith line represents pij. The matrix P will satisfy the constraints that pij = 1.0 − pji for all i ≠ j, and pii = 0.0 for all i. The end-of-file is denoted by a single line containing the number −1. Note that each of the matrix entries in this problem is given as a floating-point value. To avoid precision problems, make sure that you use either the double
data type instead of float
.
The output file should contain a single line for each test case indicating the number of the team most likely to win. To prevent floating-point precision issues, it is guaranteed that the difference in win probability for the top two teams will be at least 0.01.
2 0.0 0.1 0.2 0.3 0.9 0.0 0.4 0.5 0.8 0.6 0.0 0.6 0.7 0.5 0.4 0.0 -1Sample Output
2Hint
In the test case above, teams 1 and 2 and teams 3 and 4 play against each other in the first round; the winners of each match then play to determine the winner of the tournament. The probability that team 2 wins the tournament in this case is:
P(2 wins) | = P(2 beats 1)P(3 beats 4)P(2 beats 3) + P(2 beats 1)P(4 beats 3)P(2 beats 4) = p21p34p23 + p21p43p24 = 0.9 · 0.6 · 0.4 + 0.9 · 0.4 · 0.5 = 0.396. |
The next most likely team to win is team 3, with a 0.372 probability of winning the tournament.
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <algorithm> 5 #define INF 0x3f3f3f3f 6 7 using namespace std; 8 9 const int maxn = 200; 10 double dp[8][maxn]; 11 int sum[maxn]; 12 double a[maxn][maxn]; 13 14 int main() 15 { 16 int n; 17 while(~scanf("%d",&n) && n!=-1){ 18 int m=1<<n; 19 int s1=1<<(n-1); 20 for(int i=0;i<m;i++) 21 { 22 for(int j=0;j<m;j++) 23 { 24 scanf("%lf",&a[i][j]); 25 } 26 } 27 for(int i=0;i<m;i++) 28 dp[0][i]=1; 29 for(int i=1;i<=n;i++) 30 { 31 for(int j=0;j<m;j++) 32 { 33 int t=j/(1<<(i-1)); 34 t^=1; 35 dp[i][j]=0; 36 for(int k=t*(1<<(i-1));k<t*(1<<(i-1))+(1<<(i-1));k++) 37 { 38 dp[i][j]+=dp[i-1][j]*dp[i-1][k]*a[j][k]; 39 } 40 } 41 } 42 int ans; 43 double temp=0; 44 for(int i=0;i<m;i++) 45 { 46 if(dp[n][i]>temp) 47 { 48 ans=i; 49 temp=dp[n][i]; 50 } 51 } 52 53 printf("%d ",ans+1); 54 } 55 return 0; 56 }
C - 区间dp*2
现在有n堆石子,第i堆有ai个石子。现在要把这些石子合并成一堆,每次只能合并相邻两个,每次合并的代价是两堆石子的总石子数。求合并所有石子的最小代价。
Input第一行包含一个整数T(T<=50),表示数据组数。
每组数据第一行包含一个整数n(2<=n<=100),表示石子的堆数。
第二行包含n个正整数ai(ai<=100),表示每堆石子的石子数。
每组数据仅一行,表示最小合并代价。
Sample Input2 4 1 2 3 4 5 3 5 2 1 4Sample Output
19 33Hint
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <algorithm> 5 #include <climits> 6 7 using namespace std; 8 9 const int maxn = 105; 10 int dp[maxn][maxn],a[maxn],sum[maxn]; 11 12 int main() 13 { 14 int t,n; 15 scanf("%d",&t); 16 while(t--){ 17 scanf("%d",&n); 18 for(int i = 1;i <= n;i++){ 19 scanf("%d",&a[i]); 20 sum[i] = sum[i - 1] + a[i]; 21 } 22 memset(dp,0,sizeof(dp)); 23 for(int l = 1;l <= n;l++){ 24 for(int i = 1;i <= n - l;i++){ 25 int j = i + l; 26 dp[i][j] = INT_MAX; 27 for(int k = i;k <= j - 1;k++){ 28 dp[i][j] = min(dp[i][j],dp[i][k] + dp[k + 1][j] + sum[j] - sum[i - 1]); 29 } 30 } 31 } 32 printf("%d ",dp[1][n]); 33 } 34 return 0; 35 }