2018-08-02 DP初步

  • A  -- Race

  • Description

Disky and Sooma, two of the biggest mega minds of Bangladesh went to a far country. They ate, coded and wandered around, even in their holidays. They passed several months in this way. But everything has an end. A holy person, Munsiji came into their life. Munsiji took them to derby (horse racing). Munsiji enjoyed the race, but as usual Disky and Sooma did their as usual task instead of passing some romantic moments. They were thinking- in how many ways a race can finish! Who knows, maybe this is their romance! In a race there are n horses. You have to output the number of ways the race can finish. Note that, more than one horse may get the same position. For example, 2 horses can finish in 3 ways. 1. Both first 2. horse1 first and horse2 second 3. horse2 first and horse1 second

  • Input

Input starts with an integer T (≤ 1000), denoting the number of test cases. Each case starts with a line containing an integer n (1 ≤ n ≤ 1000).

  • Output

For each case, print the case number and the number of ways the race can finish. The result can be very large, print the result modulo 10056.

  • Sample Input

3

1

2

3

  • Sample Output

Case 1: 1

Case 2: 3

Case 3: 13

  • 题目理解

这道题是之前递推的题目,对于dp状态定义十分重要,思路是对的但是由于状态定义出现问题就会发现逻辑进行不下去了而这道题应该定义f(i,j)为i匹马获得j个名次并且全部名次都有马的情况(当i!=j的时候就是出现并列名次的情况当然是前j名而不存在没有第3名并列第4名--这和苹果放进盒子存在空盒子不同)所以ans(n)= \sum_{n}^{j=1}f(i)(j)如果i\leq j情况不合理此时结果为0      而对于f(i)(j)的转移我们可以单独拿出一个马由于每个名次都有马所以我们得到两种情况

  1. 该马单独名次,则可以得到j种名次,所有情况为j*f(i-1,j-1)                                                                                     
  2. 该马和别的马并列(说明前面i-1匹马已经占据j个名次{别忘了定义}),所有情况j*f(i-1,j)      

最后我们得到f(i,j)=j*(f(i-1,j-1)+f(i-1,j))

#include<cstdio>
const int maxn=1005;
const int mod=10056;
int dp[maxn][maxn];
int ans[maxn];
int main (){
    int t;
    scanf("%d",&t);
    dp[0][0]=1;
    for(int i=1;i<maxn;i++){
        int sum=0;
        int j;
        for(j=1;j<=i;j++){
          dp[i][j]=(dp[i-1][j-1]*j+dp[i-1][j]*j)%mod;
          sum+=dp[i][j];
          sum%=mod;
        }
        ans[i]=sum;
    }
    int Case=0;
    while(t--){
        int n;
        scanf("%d",&n);
        printf("Case %d: %d\n",++Case,ans[n]);
    }
    return 0;
}

 

  • B  -- 数字三角

  • Description

下图是个数字三角,请编写一个程序计算从顶部至底部某处一条路径,使得该路径所经过的数字总和最大。

7

3  8

8  1  0

2  7  4  4

1.  每一步可沿左斜线向下或右斜线向下走;

2.  1<=三角形行数<=100

3.  三角形中的数字为整数 0,1,……,99。

4.  如果有多种情况结果都最大,任意输出一种即可

  • Input

第一行一个整数N,代表三角形的行数

接下来N行,描述了一个数字三角

  • Output

第一行一个整数N,代表三角形的行数

接下来N行,描述了一个数字三角

  • Sample Input


7
3 8
8 1 0
2 7 4 4

  • Sample Output

25 
7 3 8 7

  • 题目理解

定义d(i,j)为第i行第j列为根的树所能到达最大值,且对于结点(i,j)来说其左、右子树的根结点为(i+1,j)(i+1,j+1)即,得到dp转移方程dp(i,j)=a(i,j)+max(dp(i+1,j),dp(i+1,j+1)),由此我们要从n行向n-1行递推,并且将子树得到的最大值更新到dp(i,j)上。路径打印只需要开一个相同维度的数组,在更新max值的时候记录下j值,对于dp值将上一行减去下一行最大子树的值,就得到这一行的累加值,即a(i,j),只要将dp数组初始化为0,最后一行也能自然输出

#include<cstdio>
#include<cstring>
const int maxn=105;
int s[maxn][maxn],load[maxn][maxn];
int main(){
   int n;
   while(scanf("%d",&n)!=EOF){
     memset(s,0,sizeof(s));
     memset(load,0,sizeof(load));
     for(int i=0;i<n;++i)
        for(int j=0;j<=i;++j)
            scanf("%d",&s[i][j]);
     //for(int i=0;i<n;++i){
        //for(int j=0;j<=i;++j)
            //printf("%d ",s[i][j]);
        //printf("\n");
     //}
     int cur=n-2;
     while(cur!=-1){
        for(int j=0;j<=cur;++j){
            int i=cur+1;
            if(s[i][j]>s[i][j+1]){
                load[cur][j]=j;
                s[cur][j]=s[cur][j]+s[i][j];
            }
            else{
                load[cur][j]=j+1;
                s[cur][j]=s[cur][j]+s[i][j+1];
            }
        }
        cur--;
     }
     printf("%d\n",s[0][0]);
     int i,j;
     for(i=0,j=0;i<=n-1;++i){
        if(i) printf(" ");
        printf("%d",s[i][j]-s[i+1][j=load[i][j]]);
        //printf("!!!%d %d\n",i,j);
     }
   }
   return 0;
}

 

  • C  -- Common Subsequence

  • Description

A subsequence of a given sequence is the given sequence with some elements (possible none) left out. Given a sequence X = < x1, x2, ..., xm > another sequence Z = < z1, z2, ..., zk > is a subsequence of X if there exists a strictly increasing sequence < i1, i2, ..., ik > of indices of X such that for all j = 1,2,...,k, x ij = zj. For example, Z = < a, b, f, c > is a subsequence of X = < a, b, c, f, b, c > with index sequence < 1, 2, 4, 6 >. Given two sequences X and Y the problem is to find the length of the maximum-length common subsequence of X and Y

  • Input

The program input is from the std input. Each data set in the input contains two strings representing the given sequences. The sequences are separated by any number of white spaces. The input data are correct

  • Output

For each set of data the program prints on the standard output the length of the maximum-length common subsequence from the beginning of a separate line

  • Sample Input

abcfbc abfcab
programming contest
abcd mnp

  • Sample Output

4
2
0

  • 题目理解

求得是两个串相同的的最大子串,定义dp(i,j)为一串长度为i,另一串长度为j所得到的最大共同子串长度

str1[i]==str2[j]转移dp(i,j)=dp(i-1,j-1)+1

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1005;
int dp[maxn][maxn];
char str1[maxn], str2[maxn];
int main()
{
    while(scanf("%s%s", str1, str2)!=EOF)
    {
        int len1 = strlen(str1);
        int len2 = strlen(str2);
        memset(dp, 0, sizeof(dp));
        for(int i = 1;i <= len1; ++i)
        {
            for(int j = 1;j <= len2; ++j)
            {
                if(str1[i-1]==str2[j-1]) dp[i][j]=dp[i-1][j-1]+1;
                else
                {
                    dp[i][j]=max(dp[i-1][j], dp[i][j-1]);
                }
            }
        }
        cout << dp[len1][len2] << endl;
    }
    return 0;
}

 

  • D  -- Longest Ordered Subsequence

  • G   --  Bridging signals

  • Description

'Oh no, they've done it again', cries the chief designer at the Waferland chip factory. Once more the routing designers have screwed up completely, making the signals on the chip connecting the ports of two functional blocks cross each other all over the place. At this late stage of the process, it is too  expensive to redo the routing. Instead, the engineers have to bridge the signals, using the third dimension, so that no two signals cross. However, bridging is a complicated operation, and thus it is desirable to bridge as few signals as possible. The call for a computer program that finds the maximum number of signals which may be connected on the silicon surface without rossing each other, is imminent. Bearing in mind that there may be housands of signal ports at the boundary of a functional block, the problem asks quite a lot of the programmer. Are you up to the task?    Figure 1. To the left: The two blocks' ports and their signal mapping (4,2,6,3,1,5). To the right: At most three signals may be routed on the silicon surface without crossing each other. The dashed signals must be bridged. 
A typical situation is schematically depicted in figure 1. The ports of the two functional blocks are numbered from 1 to p, from top to bottom. The signal mapping is described by a permutation of the numbers 1 to p in the form of a list of p unique numbers in the range 1 to p, in which the i:th number pecifies which port on the right side should be connected to the i:th port on the left side.  Two signals cross if and only if the straight lines connecting the two ports of each pair do.

  • Input

On the first line of the input, there is a single positive integer n, telling the number of test scenarios to follow. Each test scenario begins with a line containing a single positive integer p<40000, the number of ports on the two functional blocks. Then follow p lines, describing the signal mapping: On the i:th line is the port number of the block on the right side which should be connected to the i:th port of the block on the left side

  • Output

For each test scenario, output one line containing the maximum number of signals which may be routed on the silicon surface without crossing each other

  • Sample Input

4
6
4 2 6 3 1 5
10
2 3 4 5 6 7 8 9 10 1
8
8 7 6 5 4 3 2 1
9
5 8 9 2 3 1 7 4 6

  • Sample Output

3

9

1

4

  • 题目理解

G题题目都没有真正看完感觉很长很多内容,但是看图的话很明显就是一个隐藏的最长上升子序列的问题,而D题就更加明显了 ,通过dp(i)来维护长度为i的上升序列的最小结尾值,之后每增加一个数判断其是更新记录的最小值还是增加一个长度

D题代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1005;
const int inf=0x3f3f3f3f;
int dp[maxn],a[maxn];
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=0;i<maxn;++i) dp[i]=inf;
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        for(int i=0;i<n;i++)
        {
            int lct=lower_bound(dp,dp+n,a[i])-dp;
            dp[lct]=a[i];
        }
        printf("%d\n",lower_bound(dp,dp+n,inf)-dp);
    }
    return 0;
}

G题代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=40005;
const int inf=0x3fffffff;
int dp[maxn],a[maxn];
int main()
{
    int t,n;
    while(scanf("%d",&t)!=EOF)
    {
        while(t--){
          scanf("%d",&n);
          for(int i=0;i<maxn;++i) dp[i]=inf;
          for(int i=0;i<n;i++)
             scanf("%d",&a[i]);
          for(int i=0;i<n;i++)
          {
            int lct=lower_bound(dp,dp+n,a[i])-dp;
            dp[lct]=a[i];
          }
          printf("%d\n",lower_bound(dp,dp+n,inf)-dp);
        }
    }
    return 0;
}

 

  • E  -- Longest Regular Bracket Sequence

  • Description

This is yet another problem dealing with regular bracket sequences.

We should remind you that a bracket sequence is called regular, if by inserting «+» and «1» into it we can get a correct mathematical expression. For example, sequences «(())()», «()» and «(()(()))» are regular, while «)(», «(()» and «(()))(» are not.

You are given a string of «(» and «)» characters. You are to find its longest substring that is a regular bracket sequence. You are to find the number of such substrings as well

  • Input

The first line of the input file contains a non-empty string, consisting of «(» and «)» characters. Its length does not exceed 106

  • Output

Print the length of the longest substring that is a regular bracket sequence, and the number of such substrings. If there are no such substrings, write the only line containing "0 1"

  • Sample Input

)((())))(()())

  • Sample Output

6 2

  • 题目理解

题意看了好久才看明白是求最长子串以及最长子串的个数,这里关键就是一个处理的技巧,对于合法的括号串来说,其中的每一个左括号和右括号都应该是合法的。这就转换为怎么确认左/右括号是否合法。类似栈的处理,我们使用一个变量记录下左括号 的个数当遇到右括号的时候减1(与最近的左括号完成匹配),如果变量变为负数的时候这时候遇到的有括号则是不合法的(因为前面没有左括号了);将串对称的看,从后面以此方法遍历可以得到合法的左括号。接下来计算连续合法的符号长度就是子串长度,使用一个变量维护最大值

写题解的时候发现这就是一道区间dp,类似明天的回文消除问题,在后面一起讨论

//对于一个合法的串其中连续的左右括号都应该是合法的对称处理
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1000005;
char str[maxn];
bool vis[maxn];
int main()
{
    scanf("%s",str);
    int len=strlen(str);
    int cnt=0;
    memset(vis,false,sizeof(vis));
    for(int i=0;i<len;i++)
    {
        if(str[i]=='(') cnt++;
        if(str[i]==')')
        {
            if(cnt)
            {
                vis[i]=true;
                cnt--;
            }
        }
    }
    cnt=0;
    for(int i=len-1;i>=0;i--)
    {
        if(str[i]==')') cnt++;
        if(str[i]=='(')
        {
            if(cnt)
            {
                vis[i]=true;
                cnt--;
            }
        }
    }
    int ans=0,cot=0;
    cnt=0;
    for(int i=0;i<len;i++)
    {
        if(vis[i]) cnt++;
        else cnt=0;
        if(ans<cnt) ans=cnt,cot=1;
        else if(ans==cnt) cot++;
    }
    if(ans==0) cot=1;
    printf("%d %d\n",ans,cot);
    return 0;
}

 

  • H  -- Piggy-Bank

  • Description

Before ACM can do anything, a budget must be prepared and the necessary financial support obtained. The main income for this action comes from Irreversibly Bound Money (IBM). The idea behind is simple. Whenever some ACM member has any small money, he takes all the coins and throws them into a piggy-bank. You know that this process is irreversible, the coins cannot be removed without breaking the pig. After a sufficiently long time, there should be enough cash in the piggy-bank to pay everything that needs to be paid. 
But there is a big problem with piggy-banks. It is not possible to determine how much money is inside. So we might break the pig into pieces only to find out that there is not enough money. Clearly, we want to avoid this unpleasant situation. The only possibility is to weigh the piggy-bank and try to guess how many coins are inside. Assume that we are able to determine the weight of the pig exactly and that we know the weights of all coins of a given currency. Then there is some minimum amount of money in the piggy-bank that we can guarantee. Your task is to find out this worst case and determine the minimum amount of cash inside the piggy-bank. We need your help. No more prematurely broken pigs! 

  • Input

The input consists of T test cases. The number of them (T) is given on the first line of the input file. Each test case begins with a line containing two integers E and F. They indicate the weight of an empty pig and of the pig filled with coins. Both weights are given in grams. No pig will weigh more than 10 kg, that means 1 <= E <= F <= 10000. On the second line of each test case, there is an integer number N (1 <= N <= 500) that gives the number of various coins used in the given currency. Following this are exactly N lines, each specifying one coin type. These lines contain two integers each, Pand W (1 <= P <= 50000, 1 <= W <=10000). P is the value of the coin in monetary units, W is it's weight in grams

  • Output

Print exactly one line of output for each test case. The line must contain the sentence "The minimum amount of money in the piggy-bank is X." where X is the minimum amount of money that can be achieved using coins with the given total weight. If the weight cannot be reached exactly, print a line "This is impossible."

  • Sample Input

3
10 110
2
1 1
30 50
10 110
2
1 1
50 30
1 6
2
10 3
20 4

  • Sample Output

The minimum amount of money in the piggy-bank is 60.
The minimum amount of money in the piggy-bank is 100.
This is impossible

  • 题目理解

dp(v)定义为重量v下得到的最小val值,dp数组开始全部赋值为最大值,我们从0开始转移,体积一个单位增加,这时候如果重量没有超过v_{max}进行转移dp(v_{new})=min(dp(v_{pre})+val)我们只对内容不为初始值inf的重量进行转移(说明是前面转移来的为合法的,否则没法判断最后重量是否正好为v_{max})

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=10005;
const int inf=0x3f3f3f3f;
int dp[maxn],a[maxn][2];
int main()
{
    int t,v,n;
    scanf("%d",&t);
    while(t--){
        for(int i=0;i<maxn;++i) dp[i]=inf;dp[0]=0;
        int v1,v2;
        scanf("%d%d",&v1,&v2);
        v=(v2-v1);
        scanf("%d",&n);
        for(int i=0;i<n;++i)
            scanf("%d%d",&a[i][0],&a[i][1]);
        for(int i=0;i<v;++i){
            if(dp[i]!=inf)
                for(int j=0;j<n;++j){
                    v1=i+a[j][1];//printf("%d  : %d\n",i,v1);
                    if(v1<=v)
                         dp[v1]=min(dp[v1],dp[i]+a[j][0]);
                }
        }
        if(dp[v]!=inf)
            printf("The minimum amount of money in the piggy-bank is %d.\n",dp[v]);
        else
            printf("This is impossible.\n");

    }
    return 0;
}

 

  • I  -- Bone Collector

  • Description

Many years ago , in Teddy’s hometown there was a man who was called “Bone Collector”. This man like to collect varies of bones , such as dog’s , cow’s , also he went to the grave … 
The bone collector had a big bag with a volume of V ,and along his trip of collecting there are a lot of bones , obviously , different bone has different value and different volume, now given the each bone’s value along his trip , can you calculate out the maximum of the total value the bone collector can get ? 

  • Input

The first line contain a integer T , the number of cases
Followed by T cases , each case three lines , the first line contain two integer N , V, (N <= 1000 , V <= 1000 )representing the number of bones and the volume of his bag. And the second line contain N integers representing the value of each bone. The third line contain N integers representing the volume of each bone

  • Output

One integer per line representing the maximum of the total value (this number will be less than 2 31)

  • Sample Input

1
5 10
1 2 3 4 5
5 4 3 2 1

  • Sample Output

14

  • 题目理解

0-1背包问题,dp(j)代表体积j的最大value值,我们将物品按在题目给出的有序化,然后外循环扫一遍,这里由于只能使用一次,访问一次就不能使用。我们很容易得到递推公式dp(i,j)= max(dp(i-1,j-v_{i}),dp(i-1,j))如果我们对dp(i,j)降维变成dp(j)那么在推i物品时候dp(j-v_i)dp(j)应该存放的是第i-1个物品完后得到的值,有与前面坐标小的值不能被覆盖于是j倒序遍历

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1005;
int dp[maxn],a[maxn][2];
int main()
{
    int t,n,v;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&v);
        int dp[maxn],a[maxn][2];
        for(int i=0;i<n;i++) scanf("%d",&a[i][0]);
        for(int i=0;i<n;i++) scanf("%d",&a[i][1]);
        memset(dp,0,sizeof(dp));
        for(int i=0;i<n;i++){
            for(int j=v;j>=a[i][1];j--)
                dp[j]=max(dp[j],dp[j-a[i][1]]+a[i][0]);
        }
        printf("%d\n",dp[v]);
    }
    return 0;
}

 

  • J  -- Chores

  • Description

Farmer John's family pitches in with the chores during milking, doing all the chores as quickly as possible. At FJ's house, some chores cannot be started until others have been completed, e.g., it is impossible to wash the cows until they are in the stalls.
Farmer John has a list of N (3 <= N <= 10,000) chores that must be completed. Each chore requires an integer time (1 <= length of time <= 100) to complete and there may be other chores that must be completed before this chore is started. We will call these prerequisite chores. At least one chore has no prerequisite: the very first one, number 1. Farmer John's list of chores is nicely ordered, and chore K (K > 1) can have only chores 1,.K-1 as prerequisites. Write a program that reads a list of chores from 1 to N with associated times and all perquisite chores. Now calculate the shortest time it will take to complete all N chores. Of course, chores that do not depend on each other can be performed simultaneously

  • Input

* Line 1: One integer, N
* Lines 2..N+1: N lines, each with several space-separated integers. Line 2 contains chore 1; line 3 contains chore 2, and so on. Each line contains the length of time to complete the chore, the number of the prerequisites, Pi, (0 <= Pi <= 100), and the Pi prerequisites (range 1..N, of course)

  • Output

A single line with an integer which is the least amount of time required to perform all the chores

  • Sample Input

7

5 0

1 1 1

3 1 2

6 1 1

1 2 2 4

8 2 2 4

4 3 3 5 6

  • Sample Output

23

  • 题目理解

Here is one task schedule:
     Chore 1 starts at time 0, ends at time 5.
     Chore 2 starts at time 5, ends at time 6.
     Chore 3 starts at time 6, ends at time 9.
     Chore 4 starts at time 5, ends at time 11.
     Chore 5 starts at time 11, ends at time 12.
     Chore 6 starts at time 11, ends at time 19.
     Chore 7 starts at time 19, ends at time 23.
仔细读题目就能做的题,可以并发执行多个任务,所以只需要找出前面一定要完成的任务的最晚完成时间就是当前任务的最早开始时间,对所有任务完成时间取最大值就是完成所有任务的时间准确来说这个应该是一道计算题没有不定因素

#include<iostream>
#include<cstdio>
#define max(a,b) (a>b?a:b)
using namespace std;
int main()
{
    int cases,time,n,tmp,i,j,ans=0,dp[10010];
    scanf("%d",&cases);
    for(i=1;i<=cases;i++)
    {
        scanf("%d%d",&time,&n);
        dp[i]=time;
        for(j=1;j<=n;j++)
        {
            scanf("%d",&tmp);
            dp[i]=max(dp[i],dp[tmp]+time);
        }
        ans=max(dp[i],ans);
    }
    printf("%d\n",ans);
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值