4.4一周小结(dp)

今天是个不同寻常的日子,全国人民都在为那些在这场没有硝烟的战争中牺牲的人民悼念,与此同时,我在网上看到了这么一句话,瞬间让我醍醐灌顶,“这一天不是让你无聊致死,而是让你活的明白。”我想那些为国家、为人民努力付出的人们想要看见的是更多人的努力奋斗,而不是在家颓废,整天在家玩游戏。

这周依旧是做 dp的题,在又刷了一个周的题后,感觉这周开始稍微有点感觉了,拿到题之后能够先稳住心态,读明白题意,有时候发现有些题可以直接套用“模板”,就是之前所学的几个重点题型

比如下面这道题:
FatMouse believes that the fatter a mouse is, the faster it runs. To disprove this, you want to take the data on a collection of mice and put as large a subset of this data as possible into a sequence so that the weights are increasing, but the speeds are decreasing.
Input
Input contains data for a bunch of mice, one mouse per line, terminated by end of file.

The data for a particular mouse will consist of a pair of integers: the first representing its size in grams and the second representing its speed in centimeters per second. Both integers are between 1 and 10000. The data in each test case will contain information for at most 1000 mice.

Two mice may have the same weight, the same speed, or even the same weight and speed.
Output
Your program should output a sequence of lines of data; the first line should contain a number n; the remaining n lines should each contain a single positive integer (each one representing a mouse). If these n integers are m[1], m[2],…, m[n] then it must be the case that

W[m[1]] < W[m[2]] < … < W[m[n]]

and

S[m[1]] > S[m[2]] > … > S[m[n]]

In order for the answer to be correct, n should be as large as possible.
All inequalities are strict: weights must be strictly increasing, and speeds must be strictly decreasing. There may be many correct outputs for a given input, your program only needs to find one.

Sample Input
6008 1300
6000 2100
500 2000
1000 4000
1100 3000
6000 2000
8000 1400
6000 1200
2000 1900

Sample Output
4
4
5
9
7

解题思路:
我在读完这道题后发现这题与最长上升子序列那道题有几分相似,便开始往那个方向开始思考,思路是按照老鼠的体重升序排列,当体重相等时将老鼠的速度降序的顺序排列,然后求这个序列中的最长严格递增子序列。

代码如下:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
#define MAXN 1010
using namespace std;
int dp[MAXN];
int rem[MAXN];
struct fatmouse
{
    int w,s,n;
}mice[MAXN];
bool cmp(fatmouse a,fatmouse b)
{
    if(a.w==b.w)
        return a.s<b.s;
    else
        return a.w>b.w;
}
int main()
{
    int k,i,j,m,t,mark;
    for (i=1;i<MAXN;i++)
    {
        rem[i]=i;
    }
    k=1;
    while(cin >>mice[k].w>>mice[k].s)
    {
        mice[k].n=k;
        k++;
    }
    memset(dp,0,sizeof(dp));
    sort(mice+1,mice+k,cmp);
    for (i=1,m=0;i<=k;i++)
    {
        int nn=0;
        for (j=1;j<i;j++)
        {
            if(mice[i].w<mice[j].w&&mice[i].s>mice[j].s)
        {
            if(nn<dp[j])
                {
                    nn=dp[j];
                    mark=mice[j].n;
                }
        }
         if(nn)
            rem[mice[i].n]=mark;
        dp[i]=nn+1;
        if(m<dp[i])
        {
            m=dp[i];
            t=mice[i].n;
        }
        }
    }
    if(m==1)
    {
        cout <<1<<endl<<1<<endl;
    }
    else
    {
        cout <<m<<endl;
        while(rem[t]!=t)
        {
            cout <<t<<endl;
            t=rem[t];
        }
        cout <<t<<endl;
    }
    return 0;
}

不过很多题目我还是写不对状态转移方程,常常需要借助他人的题解,我觉得这就是老师所说的,积累的经验不够多,或许当做题量达到某一个点的时候,解题思路便会像泉水一样喷涌而出,要不断地去尝试新的题目才能获得之前所想不到的点。
就像下面的这道题目,我从中就获取了不少的新知识。

Given a permutation a1, a2, … aN of {1, 2, …, N}, we define its E-value as the amount of elements where ai > i. For example, the E-value of permutation {1, 3, 2, 4} is 1, while the E-value of {4, 3, 2, 1} is 2. You are requested to find how many permutations of {1, 2, …, N} whose E-value is exactly k.
Input
There are several test cases, and one line for each case, which contains two integers, N and k. (1 <= N <= 1000, 0 <= k <= N).
Output
Output one line for each case. For the answer may be quite huge, you need to output the answer module 1,000,000,007.

Sample Input
3 0
3 1

Sample Output
1
4

Hint
There is only one permutation with E-value 0: {1,2,3}, and there are four permutations with E-value 1: {1,3,2}, {2,1,3}, {3,1,2}, {3,2,1}

(感觉这人的题解写的比较清晰,带给我的感受很深)
题意:给出N,一个数列中包含从1到N的N个数,现在让这个数列进行重排,当ai>i时,这个元素对数列的E—value值贡献1。
问:给出N和k(数列的E—value值),问初始数列有多少种重排方法,使其E—value值为k。
思路:先列出1-3的的所有情况
N\K 0 1 2 3
1 1 0
2 1 1 0
3 1 4 1 0
当 n为2 ,k为 0 时有一种排列(1,2),k为1 时有一种排列(2,1)
当 n为3 ,k为 1 时只需在n为2,k为 0 和 1 的情况下插入3使E—value值加1或不变即可……
当n为2, k为 0 时,有 两个位置对E-value没有贡献,把3插入没有贡献的位置,把之前的数放到数列最后,这样E-value值则为1,有2种方法。
当n为2, k为 1 时,当前k值为所求E-value值,所有把3插入有贡献的位置,把之前的数放到最后,这样有1种方法。另外把3放到最后也是一种方法,所以有2种方法。
因此得到递推方程d[i][j]=d[i-1][j] * (j+1)+d[i-1][j-1] * (i-j)

来源:
https://blog.csdn.net/changingseasons/article/details/52224433?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522158599443119724811858445%2522%252C%2522scm%2522%253A%252220140713.130056874…%2522%257D&request_id=158599443119724811858445&biz_id=0&utm_source=distribute.pc_search_result.none-task-blog-all_SOOPENSEARCH-4

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<vector>
#include<algorithm>
#include<queue>
#include<cmath>
#include<sstream>
using namespace std;
 
typedef long long int LL;
int n,k;
LL d[1005][1005];
int mod=1e9+7;
 
int main()
{
    memset(d,0,sizeof(d));
    d[1][0]=1;d[1][1]=0;
    for(int i=1;i<=1001;i++) d[i][0]=1;
    for(int i=2;i<=1001;i++){
       for(int j=1;j<=1001;j++)
        d[i][j]=((d[i-1][j]*(j+1))%mod+(d[i-1][j-1]*(i-j))%mod)%mod;
    }
    while(~scanf("%d%d",&n,&k)){
        printf("%I64d\n",d[n][k]);
    }
    return 0;
}

这周虽然做的题并不是很多,但是在经过我自己的思考和借鉴他人的解题思路下,我感觉我对dp这一部分有了新的认识,这一部分的题目结束过后,我一定要再抽出空闲时间多仔细研究、琢磨更多的dp题目。

继续加油吧!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值