zoukankan      html  css  js  c++  java
  • DP专题·二

    1、hdu 1260 Tickets

      题意:有k个人,售票员可以选择一个人卖,或者同时卖给相邻的两个人。问最少的售票时间。

      思路:dp[i] = min(dp[i - 1] + singlep[i], dp[i - 2] + dbp[i - 1]);dp[i]表示卖到第i个人后所需最少时间。注意时间为12小时制。

     1 #include<iostream>
     2 #include<memory.h>
     3 #include<algorithm>
     4 using namespace std;
     5 int n, k;
     6 const int maxk = 2100;
     7 int dp[maxk];
     8 int singlep[maxk];
     9 int dbp[maxk];
    10 int main()
    11 {
    12     scanf("%d", &n);
    13     while (n--)
    14     {
    15         scanf("%d", &k);
    16         for (int i = 1; i <= k; i++) scanf("%d", &singlep[i]);
    17         for (int i = 1; i <= k - 1; i++) scanf("%d", &dbp[i]);
    18         memset(dp, 0, sizeof(dp));
    19         for (int i = 1; i <= k; i++)
    20         {
    21             if (i == 1)dp[i] = singlep[i];
    22             else
    23             {
    24                 dp[i] = min(dp[i - 1] + singlep[i], dp[i - 2] + dbp[i - 1]);
    25             }
    26         }
    27         int hh = 8;
    28         int mm = 0, ss = 0;
    29         hh += dp[k]/3600;
    30         mm += dp[k]%3600/ 60;
    31         ss += dp[k] % 60;
    32         char t1[4] = "am", t2[4] = "pm";
    33         printf("%02d:%02d:%02d %s
    ", (hh<=12?hh:hh-12), mm, ss, (hh >= 13 ? t2 : t1));
    34     }
    35     return 0;
    36 }
    View Code

     2、hdu 1160 FatMouse's Speed

      题意:给出若干只老鼠的重量和速度。要求找到一个最长的序列,里面每只老鼠重量严格递增,速度严格递减。

      思路:先按照速度递减排序,然后求重量递增的最长递增子序列。这里采用DP的方法,用pre数组记录前驱。

     1 #include<iostream>
     2 #include<algorithm>
     3 using namespace std;
     4 const int maxn = 1010;
     5 struct node
     6 {
     7     int w;
     8     int v;
     9     int id;
    10 }mice[maxn];
    11 int dp[maxn];
    12 int pre[maxn];
    13 bool Cmp(const node&a, const node&b)
    14 {
    15     return a.v > b.v;
    16 }
    17 void Print(int r,int num)
    18 {
    19     if (r != -1)
    20     {
    21         Print(pre[r],num+1);
    22         printf("%d
    ", mice[r].id);
    23     }
    24     else printf("%d
    ", num);
    25 }
    26 int main()
    27 {
    28     int cnt = 0;
    29     while (~scanf("%d%d", &mice[cnt].w, &mice[cnt].v))
    30     {
    31         mice[cnt].id = cnt + 1;
    32         cnt++;
    33     }
    34     sort(mice, mice + cnt, Cmp);
    35     for (int i = 0; i < cnt; i++) dp[i] = 1, pre[i] = -1;
    36     int re = 0,maxl=0;
    37     for (int i = 0; i < cnt; i++)
    38     {
    39         int ans = 0,pos=i;
    40         for (int j = 0; j < i; j++)
    41         {
    42             if (dp[j]+1 > dp[i]&&mice[i].w > mice[j].w&&mice[i].v<mice[j].v)
    43             {
    44                 dp[i] = dp[j] + 1;
    45                 pre[i] = j;
    46                 pos = j;
    47             }
    48         }
    49         if (dp[i] > maxl) maxl = dp[i], re = i;
    50     }
    51     Print(re,0);
    52     return 0;
    53 }
    View Code

    3、poj 1015 Jury Compromise

      题意:有n个候选的陪审团的人,需要从中选出m个人,使得这m个人的辩护方总分减去控诉方总分的差值最小,当最小的有多个时,选择辩护方总分加上控诉方总分最高的方案。

      思路:dp[i][j]表示选i个人、差值为j-fix中辩护方总分加上控诉方总分最高的方案。用pre[i][j]记录路径。细节见代码。

     1 #include<cstdio>
     2 #include<ctype.h>
     3 #include<algorithm>
     4 #include<iostream>
     5 #include<cstring>
     6 #include<vector>
     7 using namespace std;
     8 int dp[21][801];//dp(j, k)表示,取j 个候选人,使其辩控差为k 的所有方案中,辩控和最大的那个方案(该方案称为“方案dp(j, k)”)的辩控和。
     9 vector<int> path[21][801];
    10 
    11 int main()
    12 {
    13     int times = 1;
    14     //    freopen("input.txt","r",stdin);
    15     //    freopen("output.txt","w",stdout);
    16     int subtraction[201], _plus[201];
    17     int n, m, i, j, k;
    18     while (~scanf("%d%d", &n, &m) && n && m)
    19     {//一共有n个候选人,要选m个
    20         for (i = 0; i<m; ++i)//清空vector
    21             for (j = 0; j<801; ++j)
    22                 path[i][j].clear();
    23         memset(dp, -1, sizeof(dp));
    24         int d, p;
    25         for (i = 0; i < n; i++)
    26         {
    27             cin >> d >> p;//输入辩护方和控诉方的打分
    28             subtraction[i] = d - p;//得到每个人的辩护方的分数-控诉方的分数
    29             _plus[i] = d + p;//得到和
    30         }
    31         int fix = 20 * m;//由于题目中辩控差的值k 可以为负数,而程序中数租下标不能为负数,所以,在程序中不妨将辩控差的值都加上修正值fix=400,以免下标为负数导致出错。
    32         //为什么fix = 400?这是很显然的,m上限为20人,当20人的d均为0,p均为20时,会出现辨控差为 - 400。修正后回避下标负数问题,区间整体平移,从[-400, 400]映射到[0, 800]。
    33         dp[0][fix] = 0;
    34         for (k = 0; k < n; k++)//顺序选择一个候选人
    35             for (i = m - 1; i >= 0; i--)//进行逆推
    36             {
    37                 for (j = 0; j < 2 * fix; j++)
    38                 {
    39                     if (dp[i][j] >= 0)
    40                     {
    41                         if (dp[i + 1][j + subtraction[k]] <= dp[i][j] + _plus[k])
    42                         {//可行方案dp(j-1, x)能演化成方案dp(j, k)的必要条件是:存在某个候选人i,i 在方案dp(j-1, x)中没有被选上,且x+V(i) = k。在所有满足该必要条件的dp(j-1, x)中,选出 dp(j-1, x) + S(i) 的值最大的那个,那么方案dp(j-1, x)再加上候选人i,就演变成了方案 dp(j, k)。
    43                             //dp[i][j + d[k]] = max(dp[i][j + d[k]], dp[i-1][j] + s[k])
    44                             dp[i + 1][j + subtraction[k]] = dp[i][j] + _plus[k];
    45                             path[i + 1][j + subtraction[k]] = path[i][j];//每次更新都要把path全部复制过来,就是因为这个才用的vector
    46                             path[i + 1][j + subtraction[k]].push_back(k);
    47                         }
    48                     }
    49                 }
    50             }
    51         //DP后,从第m行的dp(m, fix)开始往两边搜索最小|D-P| 即可,第一个不为dp[m][k]!=-1的位置k就是最小|D-P|的所在。
    52         //D+P = dp(m, |D-P| ) ,|D-P|已知。
    53         //那么D = (D + P + | D - P | ) / 2, P = (D + P - | D - P | ) / 2,计算D和P时注意修正值fix
    54         for (i = 0; dp[m][fix + i] == -1 && dp[m][fix - i] == -1; i++);
    55         int temp = (dp[m][fix + i] > dp[m][fix - i]) ? i : -i;
    56         int sumD = (dp[m][fix + temp] + temp) / 2;
    57         int sumP = (dp[m][fix + temp] - temp) / 2;
    58         printf("Jury #%d
    ", times++);
    59         printf("Best jury has value %d for prosecution and value %d for defence:
    ", sumD, sumP);
    60         for (i = 0; i < m; i++)
    61             printf(" %d", path[m][fix + temp][i] + 1);
    62         printf("
    
    ");
    63 
    64     }
    65     return 0;
    66 }
    View Code

    4、hdu 1159 Common Subsequence

      题意:求两个字符串的最长公共子序列的长度。

      思路:DP模板题。dp[i][j]表示a[0]~a[i]和b[0]~b[j]的最长公共子序列的长度。dp[i][j]=dp[i-1][j-1]+1(当a[i]==b[j]);dp[i][j]=max(dp[i-1][j],dp[i][j-1])(当a[i]!=b[j])

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<string.h>
     4 using namespace std;
     5 const int maxl = 1010;
     6 char a[maxl];
     7 char b[maxl];
     8 int dp[maxl][maxl];
     9 int main()
    10 {
    11     while (~scanf("%s%s", a, b))
    12     {
    13         int la = strlen(a);
    14         int lb = strlen(b);
    15         memset(dp, 0, sizeof(dp));
    16         for (int i = 0; i < la; i++)
    17         {
    18             for (int j = 0; j < lb; j++)
    19             {
    20                 if (a[i] == b[j])
    21                 {
    22                     if (i > 0 && j > 0)dp[i][j] = dp[i - 1][j - 1] + 1;
    23                     else dp[i][j] = 1;
    24                 }
    25                 else
    26                 {
    27                     if(i>0&&j>0)dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
    28                     else if (i > 0) dp[i][j] = dp[i - 1][j];
    29                     else if (j > 0) dp[i][j] = dp[i][j - 1];
    30                     else dp[i][j] = 0;
    31                 }
    32             }
    33         }
    34         printf("%d
    ", dp[la - 1][lb - 1]);
    35     }
    36     return 0;
    37 }
    View Code

    5、poj 1661 Help Jimmy

      题意:“是男人就下一百层”的超级简化版。限制每次从平台跳下的最大高度差,求从给定的位置出发,到地面的最短时间。

      思路:dp[i][0]表示从第i层左侧跳到地面的最短时间,dp[i][1]表示从第i层右侧跳到地面的最短时间。从底向上DP,对于当前层i,从i-1层到第1层更新其最短时间。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #include<algorithm>
     5 #include<cmath>
     6 using namespace std;
     7 struct node
     8 {
     9     int x1;//板子左侧
    10     int x2;//板子右侧
    11     int h;//所在高度
    12 };
    13 node op[1010];
    14 int dp[20010][2];
    15 //dp[i][0]表示以i号平台左边为起点到地面的最短时间,dp[i][1]表示以i号平台右边为起点到地面的最短时间
    16 bool cmp(node a, node b)
    17 {//按高度从低到高
    18     return a.h < b.h;
    19 }
    20 const int inf = 0x7f7f7f7f;
    21 int main()
    22 {
    23     int t;
    24     int n, x, y, maxn;
    25     scanf("%d", &t);
    26     while (t--)
    27     {
    28         scanf("%d%d%d%d", &n, &x, &y, &maxn);
    29         for (int i = 1; i <= n; i++)
    30         {
    31             scanf("%d%d%d", &op[i].x1, &op[i].x2, &op[i].h);
    32         }
    33         sort(op + 1, op + n + 1, cmp);
    34 
    35         // 0 左
    36         // 1 右
    37         dp[1][0] = dp[1][1] = op[1].h;
    38         op[n + 1].x1 = op[n + 1].x2 = x;
    39         op[n + 1].h = y;// op[n+1] 其实代表的是坐标(x,y),最高的开始跳的地方;
    40 
    41         for (int i = 2; i <= n + 1; i++)
    42         {//从高度低的向上DP
    43             dp[i][0] = dp[i][1] = inf;
    44             int flag0 = 0; // 用于标记左面端点
    45             int flag1 = 0; // 用于标记右面端点
    46             int tmp;
    47             for (int j = i - 1; j>0; j--) // 这里注意必须逆序,因为从上往下跳,有板子挡住的话就没法继续往下跳了。
    48             {
    49                 if (op[i].h - op[j].h > maxn) continue;
    50                 if (op[j].x1 <= op[i].x1 && op[j].x2 >= op[i].x1 &&flag0 == 0)
    51                 {//可以从第i个平台的左侧跳到第j个平台上
    52                     tmp = min(dp[j][0] - op[j].x1 + op[i].x1, dp[j][1] - op[i].x1 + op[j].x2);
    53                     dp[i][0] = min(dp[i][0], tmp + op[i].h - op[j].h);
    54                     //tmp表示跳到第j个平台后向左或向右走到地面的时间的最小值
    55                     //tmp + op[i].h - op[j].h为再加上从第i个平台左侧跳到第j个平台所需要的时间
    56                     flag0 = 1; // 表示已经不能继续往下跳了,因为已经有板子了
    57                 }
    58                 if (op[j].x1 <= op[i].x2 && op[j].x2 >= op[i].x2&&flag1 == 0)
    59                 {//可以从第i个平台的右侧跳到第j个平台上
    60                     tmp = min(dp[j][0] - op[j].x1 + op[i].x2, dp[j][1] - op[i].x2 + op[j].x2);
    61                     dp[i][1] = min(dp[i][1], tmp + op[i].h - op[j].h);
    62                     flag1 = 1; // 道理同上
    63                 }
    64                 if (flag0 == 1 && flag1 == 1)break;
    65             }
    66             if (flag0 == 0 && op[i].h <= maxn)
    67             {//平台i左侧下没有其他板子,并且距离地面的高度小于等于跳的高度
    68                 dp[i][0] = min(dp[i][0], op[i].h);
    69             }
    70             if (flag1 == 0 && op[i].h <= maxn)
    71             {//平台i右侧下没有其他板子,并且距离地面的高度小于等于跳的高度
    72                 dp[i][1] = min(dp[i][1], op[i].h);
    73             }// 这里判断是不是可以直接跳到地面上。
    74              //cout << dp[i][0] << " " << dp[i][1] << endl;
    75         }
    76         int cc = min(dp[n + 1][0], dp[n + 1][1]);
    77         cout << cc << endl;
    78     }
    79     return 0;
    80 }
    View Code

     6、poj 2533 Longest Ordered Subsequence

      题意:给出一个数字序列,求最长递增子序列的长度。

      思路:模板题。

     1 #include<iostream>
     2 #include<vector>
     3 #include<algorithm>
     4 using namespace std;
     5 const int maxn = 1010;
     6 int num[maxn];
     7 int pre[maxn];
     8 int dp[maxn];
     9 int n;
    10 int DPn2()
    11 {
    12     memset(pre, -1, sizeof(pre));
    13     dp[0] = 1;
    14     int ans = 1;
    15     for (int i = 1; i < n; i++)
    16     {
    17         dp[i] = 1;
    18         for (int j = i - 1; j >= 0; j--)
    19         {
    20             if (num[i] > num[j] && dp[j] + 1 > dp[i])
    21             {
    22                 dp[i] = dp[j] + 1;
    23                 pre[i] = j;
    24             }
    25         }
    26         if (dp[i] > ans) ans = dp[i];
    27     }
    28     return ans;
    29 }
    30 int Vnlogn()
    31 {
    32     vector<int>v;
    33     for (int i = 0; i < n; i++)
    34     {
    35         if (v.empty()) v.push_back(num[i]);
    36         else if (num[i] > v.back()) v.push_back(num[i]);
    37         else
    38         {
    39             int pos = lower_bound(v.begin(), v.end(), num[i]) - v.begin();
    40             v[pos] = num[i];
    41         }
    42     }
    43     return v.size();
    44 }
    45 int main()
    46 {
    47     while (~scanf("%d", &n))
    48     {
    49         for (int i = 0; i < n; i++) scanf("%d", &num[i]);
    50         printf("%d
    ", DPn2());
    51         //printf("%d
    ", Vnlogn());
    52     }
    53     return 0;
    54 }
    View Code

     7、poj 3186 Treats for the Cows

      题意:有n个物品,每次可以从首或者尾选择商品卖出,卖出的价格为商品的价值*年份(初始时每个商品年份都为1,每卖出一个商品后剩下商品的年份+1)。问最后最大的收益值。

      思路:dp[i][j]表示卖完第i到第j的最大收益。则dp[j][j + l - 1] = max(dp[j + 1][j + l - 1] + num[j] * (n - l + 1), dp[j][j + l - 2] + num[j+l-1] * (n - l + 1));l为当前枚举的区间长度,n-l+1表示其是第n-l+1个卖出。

     1 #include<iostream>
     2 #include<memory.h>
     3 #include<algorithm>
     4 using namespace std;
     5 const int maxn = 2010;
     6 int num[maxn];
     7 int dp[maxn][maxn];//[i][j]表示从第i到第j最大的收益。
     8 int main()
     9 {
    10     int n;
    11     while (~scanf("%d", &n))
    12     {
    13         memset(dp, 0, sizeof(dp));
    14         for (int i = 1; i <= n; i++)
    15         {
    16             scanf("%d", &num[i]);
    17             dp[i][i] =num[i]* n;
    18         }
    19         for (int l=2;l<=n;l++)
    20         {
    21             for (int j = 1; j+l-1 <= n; j++)
    22             {
    23                 dp[j][j + l - 1] = max(dp[j + 1][j + l - 1] + num[j] * (n - l + 1), dp[j][j + l - 2] + num[j+l-1] * (n - l + 1));
    24             }
    25         }
    26         printf("%d
    ", dp[1][n]);
    27     }
    28     return 0;
    29 }
    View Code

     8、hdu 2859 Phalanx

      题意:给出n*n的矩阵,求最大对称子矩阵。

      思路:dp[i][j]表示左下角为(i,j)的对称矩阵的维数。可以从dp[i-1][j+1]转换。

     1 #include<iostream>
     2 #include<algorithm>
     3 using namespace std;
     4 int n;
     5 const int maxn = 1010;
     6 char mp[maxn][maxn];
     7 int dp[maxn][maxn];//dp[i][j]表示左下角为(i,j)的对称矩阵的维数。可以从dp[i-1][j+1]转换
     8 int main()
     9 {
    10     while (~scanf("%d", &n))
    11     {
    12         if (n == 0)break;
    13         for (int i = 1; i <= n; i++)
    14         {
    15             for (int j = 1; j <= n; j++) cin >> mp[i][j];
    16         }
    17         int ans = 1;
    18         for (int i = 1; i <= n; i++)
    19         {
    20             for (int j = n; j >= 1; --j)
    21             {
    22                 dp[i][j] = 1;
    23                 if (i == 1 || j == n) continue;
    24                 int ll = dp[i - 1][j + 1];
    25                 for (int k = 1; k <= ll; k++)
    26                 {
    27                     if (mp[i - k][j] == mp[i][j + k]) dp[i][j]++;
    28                     else break;
    29                 }
    30                 ans = max(ans, dp[i][j]);
    31             }
    32         }
    33         printf("%d
    ", ans);
    34     }
    35     return 0;
    36 }
    View Code

     9、poj 3616 Milking Time

      题意:共有n个小时,给出一些划分时间区间及区间内挤奶的效率,每次挤完奶后员工必须休息R小时,问如何安排,使得最后总的效率最大。

      思路:DP[i]表示到时刻i为止的最大效率。哎,好不容易一次不看题解自己推出dp过程,加油233

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<memory.h>
     4 using namespace std;
     5 int n, m, r;
     6 struct node
     7 {
     8     int st;
     9     int ed;
    10     int f;
    11 }pds[1010];
    12 int dp[2000010];
    13 bool Cmp(const node&a, const node&b)
    14 {
    15     if (a.st == b.st)return a.ed < b.ed;
    16     else return a.st < b.st;
    17 }
    18 int main()
    19 {
    20     while (~scanf("%d%d%d", &n, &m, &r))
    21     {
    22         for (int i = 1; i <= m; i++)
    23         {
    24             scanf("%d%d%d", &pds[i].st, &pds[i].ed, &pds[i].f);
    25         }
    26         
    27         sort(pds+1, pds + m+1, Cmp);
    28         pds[0].st = 0, pds[0].ed = 0, pds[0].f = 0;
    29         memset(dp, 0, sizeof(dp));
    30         int ans = 0;
    31         for (int i = 1; i <= m; i++)
    32         {
    33             int ed = pds[i].ed + r;
    34             int ee = pds[i].st;
    35             if (ed > n + r)continue;
    36             for (int j = 0; j < i; j++)
    37             {
    38                 int te;
    39                 if (j == 0) te = pds[j].ed;
    40                 else te = pds[j].ed + r;
    41                 if (te <= ee)
    42                 {
    43                     dp[ed] = max(dp[ed], dp[te] + pds[i].f);
    44                     ans = max(dp[ed], ans);
    45                 }
    46             }
    47         }
    48         printf("%d
    ", ans);
    49     }
    50     return 0;
    51 }
    View Code

     10、hdu 2955 Robberies

      题意:给出最大被抓概率maxp和银行数目,以及每个银行的能偷的钱财以及被抓的概率,求最大能偷到的钱数。

      思路:dp[i]表示偷当前钱数的最大不被抓的概率,那么取不被抓概率大于1-maxp的最大i即为答案。

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstring>
     4 using namespace std;
     5 int val[110];
     6 double w[110];
     7 double dp[10010];
     8 int main()
     9 {
    10     int t;
    11     scanf("%d", &t);
    12     while (t--)
    13     {
    14         double maxw;//被抓的概率
    15         int n;
    16         int sum = 0;
    17         scanf("%lf%d", &maxw, &n);
    18         for (int i = 0; i < n; i++) scanf("%d%lf", val + i, w + i),sum+=val[i];
    19         int maxans = 0;
    20         memset(dp, 0, sizeof(dp));
    21         dp[0] = 1;
    22         for (int i = 0; i < n; i++)
    23         {
    24             for (int v = sum; v >= val[i]; v--)
    25             {
    26                 dp[v] = max(dp[v], dp[v - val[i]] *(1-w[i]));//当前偷价值为v时不被抓的概率
    27                 if (dp[v] > 1 - maxw) maxans = max(maxans, v);
    28             }
    29         }
    30         printf("%d
    ", maxans);
    31     }
    32     return 0;
    33 }
    View Code

     11、poj 2923 Relocation

      题意:有两辆卡车,有各自的最大载重c1,c2,有n件家具,现在需要把这些家具从一个地方搬到另一个地方,问最少的搬运次数。

      思路:先状态压缩,确定所有可行的状态(所选择的货物能够在一趟内被搬运),然后对所有可行状态进行01背包(注意,转移的条件要求两种相应的状态不能有交集<即每种货物最多只会被搬运一次>),得到解。

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstdio>
     4 #include<cstring>
     5 using namespace std;
     6 const int maxst = 1 << 11;
     7 const int INF = 0x3f3f3f3f;
     8 const int maxn = 12;
     9 const int maxw = 1010;
    10 int st[maxst];//储存可行状态
    11 int dp[maxst];
    12 bool vis[maxw];
    13 int w[maxn];
    14 int n, c1, c2;
    15 bool ok(int cst)
    16 {
    17     memset(vis, 0, sizeof(vis));
    18     vis[0] = true;
    19     int sum = 0;
    20     for (int i = 0; i < n; i++)
    21     {
    22         if ((cst >> i)&1)
    23         {//如果要运走当前货物
    24             sum += w[i];
    25             for (int j = c1; j >= w[i]; j--)
    26             {
    27                 if (vis[j - w[i]]) vis[j] = true;
    28             }
    29         }
    30     }
    31     //if (cst == (1 << n) - 1) printf("%d
    ", sum);
    32     if (sum > c1 + c2) return false;
    33     for (int i = 0; i <= c1; i++)
    34     {
    35         if (vis[i] && sum - i <= c2) return true;
    36     }
    37     return false;
    38 }
    39 int main()
    40 {
    41     int t;
    42     scanf("%d", &t);
    43     int Case = 1;
    44     while (t--)
    45     {
    46         scanf("%d%d%d", &n, &c1, &c2);
    47         for (int i = 0; i < n; i++) scanf("%d", w + i);
    48 
    49         int tot = 0;
    50         int maxtot = (1 << n) - 1;
    51         for (int i = 1; i <= maxtot; i++)
    52         {
    53             dp[i] = INF;
    54             if (ok(i)) st[tot++] = i;
    55         }
    56         //对状态进行0/1背包
    57         dp[0] = 0;
    58         for (int i = 0; i < tot; i++)
    59         {
    60             for (int j = maxtot; j >= 0; j--)
    61             {
    62                 if (dp[j] == INF) continue;
    63                 if ((j&st[i]) == 0)
    64                 {
    65                     //if ((j | st[i]) == maxtot) printf("%d %d
    %d %d
    ", j, st[i], dp[j], dp[st[i]]);
    66                     dp[j | st[i]] = min(dp[j | st[i]], dp[j] + 1);
    67                 }
    68             }
    69         }
    70         printf("Scenario #%d:
    %d
    ", Case++, dp[maxtot]);//题目保证每个家具都能被运走,不存在dp[maxtot]=INF的情况
    71         if (t) printf("
    ");
    72     }
    73     return 0;
    74 }
    View Code

     12、hdu 3466 Proud Merchants

      题意:每个商人有一个货物,当你的钱不少于Qi时商人才会和你交易。问用M的钱,求买到的货物的最大价值和。

      思路:如果要先买A货物,再买B货物,那么首先需要保证Pa+Qb>Pb+Qa,即Qa-Pa<Qb-Pb,这样才能保证dp不会受到影响。

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<cstdio>
     5 using namespace std;
     6 const int maxn = 510;
     7 const int maxv = 5010;
     8 struct node
     9 {
    10     int p, q, v;
    11     friend bool operator<(const node &a, const node &b)
    12     {
    13         return a.q-a.p < b.q-b.p;
    14     }
    15 }item[maxn];
    16 int dp[maxv];
    17 int main()
    18 {
    19     int n, m;
    20     while (~scanf("%d%d", &n, &m))
    21     {
    22         for (int i = 0; i < n; i++) scanf("%d%d%d",&item[i].p,&item[i].q,&item[i].v);
    23         sort(item, item + n);
    24         memset(dp, 0, sizeof(dp));
    25         for (int i = 0; i < n; i++)
    26         {
    27             for (int j = m; j >= max(item[i].p,item[i].q); j--)
    28             {
    29                 dp[j] = max(dp[j], dp[j - item[i].p] + item[i].v);
    30             }
    31         }
    32         printf("%d
    ", dp[m]);
    33     }
    34     return 0;
    35 }
    View Code

     13、hdu 2639 Bone Collector II

      题意:求01背包第k大值

      思路:每个状态保存前k个值,用到多路归并的思想。

     1 #include<iostream>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 int val[110];
     6 int vol[110];
     7 int dp[1100][40];
     8 int pre[40];
     9 int trans[40];
    10 int main()
    11 {
    12     int t;
    13     scanf("%d", &t);
    14     while (t--)
    15     {
    16         int n, v, k;
    17         scanf("%d%d%d", &n, &v, &k);
    18         for (int i = 0; i < n; i++)  scanf("%d", val+i);
    19         for (int i = 0; i < n; i++)  scanf("%d", vol+i);
    20         memset(dp, 0, sizeof(dp));
    21         memset(pre, 0, sizeof(pre));
    22         memset(trans, 0, sizeof(trans));
    23         for (int i = 0; i < n; i++)
    24         {
    25             for (int tv = v; tv >= vol[i]; tv--)
    26             {
    27                 for (int j = 0; j < k; j++)
    28                 {
    29                     pre[j] = dp[tv][j];
    30                     trans[j] = dp[tv - vol[i]][j]+val[i];
    31                 }
    32                 int id1 = 0, id2 = 0, cur = 0;
    33                 while (cur < k && (id1 < k || id2 < k))
    34                 {
    35                     if (pre[id1] >= trans[id2]) dp[tv][cur] = pre[id1++];
    36                     else dp[tv][cur] = trans[id2++];
    37                     if (cur == 0)cur++;
    38                     else if (dp[tv][cur] != dp[tv][cur - 1]) cur++;
    39                 }
    40             }
    41         }
    42         printf("%d
    ", dp[v][k - 1]);
    43     }
    44     return 0;
    45 }
    View Code

    14、poj 2184 Cow Exhibition

      题意:每头牛都有funny值fi和smart值si(有正负),现在需要选出一些牛,使得所有牛的funny值之和TF与smart值之和TS不小于0,同时TS+TF最大。

      思路:因为有负值,所以向右偏移;然后求每个对应的TF下的最大TS。如果s[i]大于0,则dp[v]从dp[v-s[i]]转移过来。因为当前容量为正,则相当于从v-s[i]加上s[i],然后加上价值f[i];如果s[i]小于0,则dp[v]从dp[v-s[i]]即dp[v+|s[i]|]转移过来。因为当前容量为负,则相当于从v+|s[i]|减去|s[i]|,然后加上价值f[i].

     1 //基本思路:找到当前ts下最大的tf.之后找最大的ts+tf
     2 
     3 #include<iostream>
     4 #include<cstring>
     5 #include<algorithm>
     6 #include<cstdio>
     7 using namespace std;
     8 int s[110];
     9 int f[110];
    10 const int maxv = 200100;
    11 const int INF = 0x3f3f3f3f;
    12 int dp[maxv];
    13 int main()
    14 {
    15     int n;
    16     while (~scanf("%d", &n))
    17     {
    18         for (int i = 0; i < n; i++)
    19         {
    20             scanf("%d%d", s + i, f + i);
    21         }
    22         int sumv =n*2000;
    23         memset(dp, -INF, sizeof(dp));
    24         int SHIFT = n*1000;
    25         dp[SHIFT] = 0;
    26         for (int i = 0; i < n; i++)
    27         {
    28             if (s[i] >= 0)
    29             {/*如果s[i]大于0,则dp[v]从dp[v-s[i]]转移过来。因为当前容量为正,则相当于从v-s[i]加上
    30                s[i],然后加上价值f[i]*/
    31                 for (int v = sumv; v >= s[i]; v--) dp[v] = max(dp[v], dp[v - s[i]] + f[i]);
    32             }
    33             else
    34             {/*如果s[i]小于0,则dp[v]从dp[v-s[i]]即dp[v+|s[i]|]转移过来。因为当前容量为负,则相当于从v+|s[i]|减去
    35                |s[i]|,然后加上价值f[i]*/
    36                 for (int v = 0; v <= sumv + s[i]; v++) dp[v] = max(dp[v], dp[v - s[i]] + f[i]);
    37             }
    38         }
    39         int ans = 0;
    40         for (int i = SHIFT; i <= sumv; i++)
    41         {
    42             if(dp[i]>=0)ans = max(ans, dp[i] + i - SHIFT);
    43         }
    44         printf("%d
    ", ans);
    45     }
    46     return 0;
    47 }
    View Code

    15、uva 562 Dividing coins

      题意:需要把所有硬币分成两堆,使得两堆价值差最小。

      思路:设置容量为所有硬币的总价值/2,然后dp.

     1 #include<iostream>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int maxn = 110;
     6 const int maxw = 50010;
     7 int dp[maxw];
     8 int w[maxn];
     9 int main()
    10 {
    11     int t;
    12     scanf("%d", &t);
    13     while (t--)
    14     {
    15         int n;
    16         scanf("%d", &n);
    17         int sum = 0;
    18         for (int i = 0; i < n; i++)
    19         {
    20             scanf("%d", &w[i]);
    21             sum += w[i];
    22         }
    23         int cmax = sum / 2;
    24         memset(dp, 0, sizeof(dp));
    25         for (int i = 0; i < n; i++)
    26         {
    27             for (int cw = cmax; cw >= w[i]; cw--)
    28             {
    29                 dp[cw] = max(dp[cw], dp[cw - w[i]] + w[i]);
    30             }
    31         }
    32         printf("%d
    ", sum - 2 * dp[cmax]);
    33     }
    34     return 0;
    35 }
    View Code

     16、uva 624 CD

      题意:需要把一些CD刻录在磁带上,问最多能够刻录的时长是多少?

      思路:简单01背包,注意记录。

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<vector>
     5 #include<cstdio>
     6 using namespace std;
     7 const int maxn = 20000;
     8 int Time[25];
     9 int vis[25][maxn];
    10 int dp[maxn];
    11 int main()
    12 {
    13     int n, num;
    14     while (~scanf("%d", &n))
    15     {
    16         scanf("%d", &num);
    17         for (int i = 1; i <= num; i++)
    18         {
    19             scanf("%d", &Time[i]);
    20         }
    21         memset(dp, 0, sizeof(dp));
    22         memset(vis, -1,sizeof(vis));
    23         for (int i = 1; i <= num; i++)
    24         {
    25             for (int j = n; j >= Time[i]; j--)
    26             {
    27                 if (dp[j - Time[i]] + Time[i] > dp[j])
    28                 {
    29                     dp[j] = dp[j - Time[i]] + Time[i];
    30                     vis[i][j] = i;
    31                 }
    32             }
    33         }
    34         vector<int>Order;
    35         int  w = n;
    36         for (int i = num; i >= 1; --i)
    37         {
    38             if (vis[i][w] != -1)
    39             {
    40                 Order.push_back(Time[vis[i][w]]);
    41                 w -= Time[vis[i][w]];
    42             }
    43         }
    44         int sz = Order.size();
    45         for (int i = sz - 1; i >= 0; i--) printf("%d ", Order[i]);
    46         printf("sum:%d
    ", dp[n]);
    47     }
    48     return 0;
    49 }
    View Code

    17、hdu 2546 饭卡

      题意:当卡上余额大于等于5元时,一定可以购买成功一样菜(无论该菜的价格是否大于5元)。求最小的余额数

      思路:先用当前拥有的额度-5元去买除最贵菜之外的菜,再用剩下的钱去买那个最贵的菜。

     1 #include<iostream>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<cstdio>
     5 using namespace std;
     6 const int maxn = 1010;
     7 const int maxm = 1010;
     8 int price[maxn];
     9 int dp[maxm];
    10 int main()
    11 {
    12     int n;
    13     while (~scanf("%d", &n) && n)
    14     {
    15         for (int i = 1; i <= n; i++) scanf("%d", &price[i]);
    16         int inim;
    17         scanf("%d", &inim);
    18         if (inim < 5)
    19         {
    20             printf("%d
    ", inim);
    21             continue;
    22         }
    23         inim -= 5;//保留5元,用5元去买最贵的菜
    24         sort(price + 1, price + 1 + n);
    25         memset(dp, 0, sizeof(dp));//dp[i]表示用i块钱能够买的菜总花费最高
    26         for (int i = 1; i <=n-1; i++)
    27         {
    28             for (int j = inim; j >= price[i]; --j)
    29             {
    30                 dp[j] = max(dp[j], dp[j - price[i]] + price[i]);
    31             }
    32         }
    33         printf("%d
    ",inim+5-dp[inim]-price[n]);
    34     }
    35     return 0;
    36 }
    View Code

    18、poj 3624 Charm Bracelet

      题意:需要串手链,使得总重不超过M的情况下Di之和最大

      思路:01背包

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstdio>
     4 using namespace std;
     5 const int maxn = 3600;
     6 const int maxw = 13000;
     7 int rat[maxn];
     8 int wt[maxn];
     9 int dp[maxw];
    10 int main()
    11 {
    12     int n, m;
    13     scanf("%d%d", &n, &m);
    14     for (int i = 1; i <= n; i++) scanf("%d%d", &wt[i], &rat[i]);
    15     for (int i = 1; i <= n; i++)
    16     {
    17         for (int v = m; v >= wt[i]; v--)
    18         {
    19             dp[v] = max(dp[v], dp[v - wt[i]] + rat[i]);
    20         }
    21     }
    22     printf("%d
    ", dp[m]);
    23     return 0;
    24 }
    View Code

    19、hdu 2602 Bone Collector

      题意:需要收集骨头,在不超过背包容量的情况下求最大价值。

      思路:01背包

     1 #include<iostream>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<cstdio>
     5 using namespace std;
     6 const int maxn = 1010;
     7 const int maxv = 1010;
     8 int vali[maxn];
     9 int voli[maxn];
    10 int dp[maxv];
    11 int main()
    12 {
    13     int t;
    14     int n, mv;
    15     scanf("%d", &t);
    16     while (t--)
    17     {
    18         scanf("%d%d", &n, &mv);
    19         for (int i = 1; i <= n; i++) scanf("%d", &vali[i]);
    20         for (int i = 1; i <= n; i++) scanf("%d", &voli[i]);
    21         memset(dp, 0, sizeof(dp));
    22         for (int i = 1; i <= n; i++)
    23         {
    24             for (int j = mv; j >= voli[i]; j--)
    25             {
    26                 dp[j] = max(dp[j], dp[j - voli[i]] + vali[i]);
    27             }
    28         }
    29         printf("%d
    ",dp[mv]);
    30     }
    31     return 0;
    32 }
    View Code
  • 相关阅读:
    some tips
    ORA00847: MEMORY_TARGET/MEMORY_MAX_TARGET and LOCK_SGA cannot be set together
    Chapter 01Overview of Oracle 9i Database Perfomrmance Tuning
    Chapter 02Diagnostic and Tuning Tools
    变量与常用符号
    Chapter 18Tuning the Operating System
    标准输入输出
    Trace files
    DBADeveloped Tools
    Chapter 03Database Configuration and IO Issues
  • 原文地址:https://www.cnblogs.com/ivan-count/p/7337799.html
Copyright © 2011-2022 走看看