4月11日

poj3616

题意:奶牛在1到n时间段内产奶,总共有m个产奶区间,买个区间有开始时间和结束时间,还有产奶量,同时每次产完奶需要休息一定的时间,求最大产奶量

分析:比较简单的dp,有点像最长上升子序列的变种,把产奶时间按开始时间排序,对于开始时间大于前面结束时间的点,求其最大的产奶量

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <string>
 5 #include <vector>
 6 #include <algorithm>
 7 #include <set>
 8 #include <map>
 9 #include <bitset>
10 #include <cmath>
11 #include <queue>
12 #include <stack>
13 using namespace std;
14 const int maxn=1500;
15 int dp[maxn];
16 typedef struct p
17 {
18     int start,over,value;
19 }p;
20 int n,m,r;
21 bool cmp(p a,p b)
22 {
23     return a.start<b.start;
24 }
25 int main()
26 {
27     while(cin>>n>>m>>r)
28     {
29         p s[maxn];
30         for(int i=0;i<m;i++)
31         {
32             cin>>s[i].start>>s[i].over>>s[i].value;
33             s[i].over+=r;
34         }
35         sort(s,s+m,cmp);
36         memset(dp,0,sizeof(dp));
37         for(int i=0;i<m;i++)
38         {
39             dp[i]=s[i].value;
40             for(int j=0;j<i;j++){
41                 if(s[i].start>=s[j].over)
42                     dp[i]=max(dp[i],dp[j]+s[i].value);
43             }
44         }
45         int mx=0;
46         for(int i=0;i<m;i++)
47             mx=max(mx,dp[i]);
48         cout<<mx<<endl;
49     }
50     return 0;
51 }
View Code

有关划分数的问题:

n个无区别的物体,划分成不超过m组,求划分方法数。

分析:这个问题被称为n的m划分。设n的m划分是ai,(i=1.....m)(a1+a2+...+am=n),若没个ai>0,则{ai-1}对应n-m的m划分。若存在ai=0,则对应了n的m-1划分。令dp[i][j]为j的i划分,dp[i][j]=dp[i-1][j]+dp[i][j-i];

 1 int dp[maxn][maxn];
 2 void solve()
 3 {
 4     dp[0][0]=1;
 5     for(int i=1;i<=m;i++){
 6         for(int j=0;j<=n;j++)
 7         {
 8             if(j-i>=0)
 9                 dp[i][j]=dp[i-1][j]+dp[i][j-i];
10             else
11                 dp[i][j]=dp[i-1][j];
12         }
13     }
14 }
View Code

 poj3280(区间dp)

题意:可以在任意位置增删字符,增删有不同代价,求能构成回文串的最小代价,题解说是取的是增加和删除的最小代价

分析:dp[i][j]表示i到j构成回文串的最小代价,如果s[i]=s[j],那么dp[i][j]=dp[i+1][j-1],若不想等,我们知道对于任何一个区间,增加和删除一个字符都不会对原有区间产生影响,所以只用求dp[i+1][j]和dp[i][j-1]当中的最小值即可。非常感谢夹克爷给我的耐心讲解,开始还不太理解这题

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <string>
 5 #include <vector>
 6 #include <algorithm>
 7 #include <set>
 8 #include <map>
 9 #include <bitset>
10 #include <cmath>
11 #include <queue>
12 #include <stack>
13 using namespace std;
14 const int maxn=2020;
15 int dp[maxn][maxn];
16 char s[maxn];
17 int n,m;
18 int vis[30];
19 int main()
20 {
21     while(cin>>n>>m)
22     {
23         cin>>s;
24         memset(dp,0,sizeof(dp));
25         memset(vis,0,sizeof(vis));
26         for(int i=0;i<n;i++)
27         {
28             char c;
29             int start,over;
30             cin>>c>>start>>over;
31             vis[c-'a']=min(start,over);
32         }
33         for(int i=m-1;i>=0;i--)
34         {
35             for(int j=i+1;j<m;j++)
36             {
37                 if(s[i]==s[j])
38                     dp[i][j]=dp[i+1][j-1];
39                 else
40                     dp[i][j]=min(dp[i+1][j]+vis[s[i]-'a'],dp[i][j-1]+vis[s[j]-'a']);
41             }
42         }
43         cout<<dp[0][m-1]<<endl;
44     }
45     return 0;
46 }
View Code

 51nod 1092(区间dp)

最后再来一道一样的题目,不过更为简单,求最小添加多少字符可以构成回文串

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <string>
 5 #include <vector>
 6 #include <algorithm>
 7 #include <set>
 8 #include <map>
 9 #include <bitset>
10 #include <cmath>
11 #include <queue>
12 #include <stack>
13 using namespace std;
14 const int maxn=1010;
15 char s[maxn];
16 int dp[maxn][maxn];
17 int n;
18 int main()
19 {
20     while(cin>>s)
21     {
22         memset(dp,0,sizeof(dp));
23         n=strlen(s);
24         for(int i=n-1;i>=0;i--)
25         {
26             for(int j=i+1;j<n;j++)
27             {
28                 if(s[i]==s[j])
29                     dp[i][j]=dp[i+1][j-1];
30                 else
31                     dp[i][j]=min(dp[i+1][j],dp[i][j-1])+1;
32             }
33         }
34         cout<<dp[0][n-1]<<endl;
35     }
36     return 0;
37 }
View Code
原文地址:https://www.cnblogs.com/wolf940509/p/5377479.html