zoukankan      html  css  js  c++  java
  • 动态规划水题集

    对于巨佬而言真的就是水题了,作为一个蒟蒻我还是从水题开始慢慢写吧

    hdu 2602 Bone Collector

    01背包模板题,用这道题写写01背包的几种写法吧

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1100;
    int val[maxn];
    int pla[maxn];
    int dp[maxn][maxn];
    int N,V;
    void solve()
    {
    	for (int i=1;i<=N;i++)
    	{
    		for (int j=0;j<=V;j++)
    		{
    			if (j>=pla[i])
    				dp[i][j]=max(dp[i-1][j],dp[i-1][j-pla[i]]+val[i]);
    			else
    				dp[i][j]=dp[i-1][j];
    		}
    	}
    }
    int choose[maxn];//这个是用来记录选择了哪个物品的
    int main()
    {
    	int T;
    	cin>>T;
    	while (T--)
    	{
    		memset(dp,0,sizeof(dp));
    		cin>>N>>V;
    		for (int i=1;i<=N;i++) cin>>val[i];
    		for (int i=1;i<=N;i++) cin>>pla[i];
    		solve();
    		cout<<dp[N][V]<<endl;//忘了写endl搞了个PE...
    		/*int n=N,v=V;这一段就是找寻找物品的,我就注释掉了
    		while (dp[n][v])一直循环找选择的物品
    		{
    			if (dp[n][v]==dp[n-1][v])
    				choose[n]=0;
    			else
    			{
    				choose[n]=1;
    				v=v-pla[n];开始忘了减...
    			}
    			n--;
    		}
    		for (int i=1;i<=N;i++)
    			cout<<choose[i]<<" ";*/
    	}
    	return 0;
    }
    
    
    //滚动数组的代码
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1100;
    int val[maxn];
    int pla[maxn];
    int dp[maxn];
    int N,V;
    void solve()
    {
    	for (int i=1;i<=N;i++)
    		for (int j=V;j>=pla[i];j--)//最开始还多写了个if来判断j是不是大于pla[i],看了看AC代码发现写一起就行了...还是太弱
    				dp[j]=max(dp[j],dp[j-pla[i]]+val[i]);//标准背包状态转移方程
    }
    int main()
    {
    	int T;
    	cin>>T;
    	while (T--)
    	{
    		memset(dp,0,sizeof(dp));//别忘了清0
    		cin>>N>>V;
    		for (int i=1;i<=N;i++) cin>>val[i];
    		for (int i=1;i<=N;i++) cin>>pla[i];
    		solve();
    		cout<<dp[V]<<endl;
    	}
    	return 0;
    }
    
    

    hdu 1024 Max Sum Plus Plus

    真的是除了模板题我都不会啊,这道应该算是我第一个真正的dp题了

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6+10;
    int dp[maxn];
    int num[maxn];
    int temp[maxn];
    int main()
    {
    	int n,m,t;
    	while (~scanf("%d %d",&m,&n))
    	{
    		memset(dp,0,sizeof(dp));
    		memset(temp,0,sizeof(temp));
    		for (int i=1;i<=n;i++)
    			scanf("%d",&num[i]);
    		for (int i=1;i<=m;i++)
    		{
    			t=-1e9;
    			for (int j=i;j<=n;j++)
    			{
    				dp[j]=max(temp[j-1],dp[j-1])+num[j];
    				temp[j-1]=t;
    				t=max(t,dp[j]);
    			}
    		}
    		printf("%d
    ",t);
    	}
    
    	return 0;
    }
    
    

    hdu 4576 Robot

    或许这才是我自己能够半独立想出来的第一道题?主程序好歹是自己写的,但是的确看了题解而且改了改才写好的。

    题意:有一个格子数量为n的环,给m个操作,机器人可能向左可能向右,几率相同为50%,问在l~r之间的概率。

    最开始一看,这不用模拟还能咋做?但是指数级的增长速度啊!后面看到这样一句话懂了,第i号格子其实就是只能由 i-w号格子 与i+w号格子得来,那把每个都推一遍就好了啊,就可以优化到n*m的复杂度了。我也不知道我怎么运用了dp的思想,反正多做点题吧。

    还有,这道题用了滚动数组的思想,因为下一次所在的位置是这一次决定的,所以要用两个数组来回滚。也就是q[maxn],p[maxn]

    最后,这道题有点卡常数,不要用cin,cout

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=210;
    int n,m,l,r;
    double p[maxn],q[maxn];
    int main()
    {
    	while (scanf("%d%d%d%d",&n,&m,&l,&r)!=EOF && (n||m||l||r) )//正确的结束写法
    	{
    		double res=0;
    		for (int i=0;i<=n;i++) q[i]=p[i]=0;
    		q[0]=1.0;
    		while (m--)
    		{
    			int tem;
    			scanf("%d",&tem);
    			for (int i=0;i<n;i++)
    			{
    				if (q[i]>0)
    				{
    					int a=(i+tem)%n;
    					int b=((i-tem)%n+n)%n;//环里面必须这样写
    					p[a]+=q[i]*0.5;
    					p[b]+=q[i]*0.5;
    				}
    			}
    			for (int i=0;i<n;i++)
    			{
    				q[i]=p[i];
    				p[i]=0;
    			}
    		}
    		for (int i=l-1;i<r;i++)
    			res+=q[i];
    		printf("%.4lf
    ",res);
    	}
        return 0;
    }
    

    hdu 1159 Common Subsequence

    公共最长子序列模板题,理解了背包之后再看也不算太难

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn=1e3+10;
    
    int dp[maxn][maxn];
    
    int main()
    {
    	string a,b;
    	while (cin>>a>>b)
    	{
    		memset(dp,0,sizeof(dp));
    		for (int i=1;i<=a.length();i++)
    		{
    			for (int j=1;j<=b.length();j++)
    			{
    				if (a[i-1]==b[j-1])//注意字符数组下标从0开始
    					dp[i][j]=dp[i-1][j-1]+1;
    				else
    					dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
    			}//状态转移方程
    		}
    		cout<<dp[a.length()][b.length()]<<endl;
    		/*stack<char> v;
    		int la=a.length(),lb=b.length();
    		while (dp[la][lb])
    		{
    			if (a[la-1]==b[lb-1])
    			{
    				v.push(a[la-1]);
    				la--,lb--;
    			}
    			else
    			{
    				if (dp[la][lb]==dp[la-1][lb])
    					la--;
    				else
    					lb--;
    			}
    		}
    		while (!v.empty()){cout<<v.top();v.pop();}*/
            //用于输出最长公共子序列的,感觉和01背包差不多
    	}
        return 0;
    }
    
    

    hdu 1257 最少拦截系统

    按照书里的方法,我把两种DP写法都写一遍吧。

    首先,这道题字面意思时求一个序列中单调递减子序列有多少个,等价于求最长上升子序列中元素的个数

    • 用最长公共子序列的方法求解

    最开始看到这个我都惊了,没想到还能这样。首先把题目给的序列再复制一份,对其中一份从小到大排个序,求它们两个序列的最长公共子序列就行了。woc,还能这样?

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=1e4+10;
    int dp[maxn][maxn];
    int p[maxn],pp[maxn];
    int main()
    {
        int n;
        while (cin>>n)
        {
            for (int i=1;i<=n;i++)
            {
                cin>>p[i];
                pp[i]=p[i];
            }
            sort(p+1,p+n+1);
            for (int i=1;i<=n;i++)
            {
                for (int j=1;j<=n;j++)
                {
                    if (p[i]==pp[j])
                        dp[i][j]=dp[i-1][j-1]+1;
                    else
                        dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
                }
            }
            cout<<dp[n][n]<<endl;
        }
        return 0;
    }
    
    • dp方法求解

    这道题的dp不同于01背包,最长公共子序列。上述两种至少它的状态表示还比较容易理解,但是LIS的 f(i) 代表的是以第i个数结尾的最长递增子序列的长度,u1s1不太好想。

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=1e4+10;
    int dp[maxn];
    int p[maxn];
    int main()
    {
    	int n;
    	while (cin>>n)
    	{
    		for (int i=1;i<=n;i++)
    		{
    			cin>>p[i];
    			dp[i]=1;//初始化,自身也算一个序列
    		}
    		for (int i=2;i<=n;i++)
    			for (int j=1;j<i;j++)
    				if (p[i]>p[j])//状态转移方程
    					dp[i]=max(dp[i],dp[j]+1);
    		int ans=dp[max_element(dp,dp+n+1)-dp];
    		cout<<ans<<endl;
    	}
        return 0;
    }
    

    hdu 2018 母牛的故事

    这道题要用递推。把每一年未成熟的和成熟的分开来看就很容易找到规律。

    问题就出在我知道规律但是代码还是有问题,如果给的初始条件少会使时间线后移...

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=1e4+10;
    int young[65],old[65];
    int solve (int n)
    {
    	if (young[n]!=-1&&old[n]!=-1)
    		return young[n]+old[n];
    	if (young[n]!=-1)
    	{
    		old[n]=solve(n-3);
    		return old[n]+young[n];
    	}
    	if (old[n]!=-1)
    	{
    		young[n]=solve(n-1);
    		return old[n]+young[n];
    	}
    	young[n]=solve(n-1);
    	old[n]=solve(n-3);
    	return old[n]+young[n];
    }
    int main()
    {
    	for (int i=0;i<65;i++)
    		young[i]=old[i]=-1;
    	old[1]=old[2]=old[3]=old[4]=1;
    	solve(55);
    	int n;
    	while (cin>>n&&n)
    		cout<<young[n]+old[n]<<endl;
        return 0;
    }
    
  • 相关阅读:
    关于session
    信息查找界面
    Java8 新特性 (三)Java内置的函数式接口
    第二节:表的管理
    【LeetCode-数组】有序数组中的单一元素
    【LeetCode-字符串】一次编辑
    【LeetCode-贪心】跳跃游戏 II
    【LeetCode-数组】三个数的最大乘积
    学习进度条94
    学习进度条93
  • 原文地址:https://www.cnblogs.com/Salty-Fish/p/12497499.html
Copyright © 2011-2022 走看看