DSA二组讲题2021.11.11

P1024 一元三次方程求解

#include <bits/stdc++.h>
using namespace std;
double a,b,c,d;
double fc(double x)
{
    return a*x*x*x+b*x*x+c*x+d;
}
int main()
{
    double l,r,m,x1,x2;
    int s=0; //s用来计数
    scanf("%lf%lf%lf%lf", &a, &b, &c, &d);  //输入
    for (int i = -100; i < 100; i++)
    {
        l=i; 
        r=i+1;
        x1=fc(l); 
        x2=fc(r);
        if(!x1) 
        {
            printf("%.2lf ",l); 
            s++;
        }      //判断左端点,是零点直接输出
        //不能判断右端点,会重复,因为右端点是左端点加一,下一次循环就会重复
        if(x1*x2<0)                             //区间内有根。
        {
            while(r-l>=0.001)                     //二分控制精度。
            {
                m=(l+r)/2;
                if(fc(m)*fc(r)<=0) 
                   l=m; 
                else 
                   r=m;   //计算中点处函数值缩小区间。
            }
            printf("%.2lf ",l);  
            //这里输出左右端点都是一样的,输出中间值m也可以
            s++;
        }
        if (s==3) 
            break;             
            //找到三个就退出大概会省一点时间
    }
    return 0;
}
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
   double a,b,c,d;
   scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
   for(double i=-100;i<=100;i+=0.001)
   {
      double j=i+0.001;
      double y1=a*i*i*i+b*i*i+c*i+d;
      double y2=a*j*j*j+b*j*j+c*j+d;
      if(y1>=0&&y2<=0||y1<=0&&y2>=0)
      {
         double x=(i+j)/2;
         printf("%.2lf ",x);
      }
   }
}

P1048 采药

01背包

1.不选,然后去考虑下一个

2.选,背包容量减掉那个重量,总值加上那个价值。

1 2 3 4
吉他 占一格 1500元 1500 1500 1500 1500
音响 占四格 3000元 1500 1500 1500 3000
笔记本电脑 占三格 2000元 1500 1500 2000 3500
#include <bits/stdc++.h>
using namespace std;
int w[105],val[105];
int dp[105][1005];
int main()
{
    int t,m,res=-1;
    scanf("%d%d",&t,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&w[i],&val[i]);
    }
    for(int i=1;i<=m;i++)     //i理解为物品,j理解为空间
        for(int j=0;j<=t;j++)  
        {
          dp[i][j]=dp[i-1][j];//这就是直接什么都不选,所以就是上一行的数据
            if(j>=w[i])//位置可以装下的话
            {
                dp[i][j]=max(dp[i-1][j-w[i]]+val[i],dp[i-1][j]);//比较这次不拿和拿了再加上价值哪个大
            }  都是用i-1行的数据
        }
    printf("%d",dp[m][t]);//输出最后一行最后一列就是考虑了所有物品、最大空间的最大价值
    return 0;
}
#include <bits/stdc++.h>
using namespace std;
int w[105], val[105];
int dp[1005];//只存储价值
int main()
{
    int t,m,res=-1;    
    scanf("%d%d",&t,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&w[i],&val[i]);
    }
    for(int i=1;i<=m;i++) //还是从第一个物品开始循环
    {
        for(int j=t;j>=0;j--) //从最大容量开始看,防止前面的被覆盖,使得后面的出错
        {
            if(j>=w[i])
            {
                dp[j]=max(dp[j-w[i]]+val[i], dp[j]);
            }
        }
    }    
    printf("%d",dp[t]);
    return 0;
}

P1616 疯狂的采药

本题数据范围较大,需要开long long

状态转移方程推导

完全背包的状态转移方程:dp(i,j)=max(dp(i-1,j),dp(i,j-v)+val[i]) 这里第二项就不是i-1了,是i了,也正是因为是i,所以一维优化时正着来

就是要么是左边的,要么是上方的

完全背包问题

完全背包的一维优化

dp[j]=max(dp[j],dp[j-v]+w)

AC代码

#include <bits/stdc++.h>
using namespace std;
const int maxm = 10010, maxt = 10000010;
long long v[maxm], t[maxm], f[maxt];//开long long!
int main()
{
	int T , m;
	cin >> T >> m;
	for(int i = 1;i <= m ;i ++) 
	    cin >> t[i] >> v[i];
	for(int i = 1;i <= m;i ++)
		for(int j = 0;j <= T;j++)/*完全背包必须正着来,需要覆盖
		                            0-1背包必须反着来,不能被覆盖*/
		    if(j>=t[i])
			    f[j] = max(f[j],f[j - t[i]] + v[i]);
	cout << f[T];
}

P1064 金明的预算方案

01背包

1.不选,然后去考虑下一个

2.选,背包容量减掉那个重量,总值加上那个价值。

本题选择情况

1.不选,然后去考虑下一个

2.选且只选这个主件

3.选这个主件,并且选附件1

4.选这个主件,并且选附件2

5.选这个主件,并且选附件1和附件2.

这五种情况就会带来四次的max函数比较

#include <bits/stdc++.h>
#define maxn 32005
using namespace std;
int n,m;
int v,p,q;
int main_item_w[maxn];//主物件的价格
int main_item_c[maxn];//主物件的重要度
int annex_item_w[maxn][3];//附件的价格
int annex_item_c[maxn][3];//附件的重要度
int f[maxn];
int main(){
    cin >> n >> m;//总钱数n,可以购买的主物件m件
    for (int i=1;i<=m;i++){
        cin >> v >> p >> q;//v,p,q分别代表价格,重要度,它属于的主物件,q如果等于0,则自己就是主物件
        if (!q){//自己是主物件
            main_item_w[i] = v;
            main_item_c[i] = v * p;//本题目中最终需要的价值 = 重要度 * 价格
        }
        else{//自己不是主物件
            annex_item_w[q][0]++;//这里存储的是自己是第几个附件
            annex_item_w[q][annex_item_w[q][0]] = v;//属于主物件q的第annex_item_w[q][0]个附件的价格
            annex_item_c[q][annex_item_w[q][0]] = v * p;//属于主物件q的第annex_item_w[q][0]个附件的价值
        }
    }

    for (int i=1;i<=m;i++)
        for (int j=n;main_item_w[i]!=0 && j>=main_item_w[i];j--){
        //j=n倒着来,循环终止条件为主物品不等于0且j不小于本件主物品的价格
            f[j] = max(f[j],f[j-main_item_w[i]]+main_item_c[i]);//不选附件

            if (j >= main_item_w[i] + annex_item_w[i][1])//选择附件1
                f[j] = max(f[j],f[ j - main_item_w[i] - annex_item_w[i][1] ] + main_item_c[i] + annex_item_c[i][1]);

            if (j >= main_item_w[i] + annex_item_w[i][2])//选择附件2
                f[j] = max(f[j],f[ j - main_item_w[i] - annex_item_w[i][2] ] + main_item_c[i] + annex_item_c[i][2]);

            if (j >= main_item_w[i] + annex_item_w[i][1] + annex_item_w[i][2])//附件1和附件2都选择
                f[j] = max(f[j],f[ j - main_item_w[i] - annex_item_w[i][1] - annex_item_w[i][2] ] + main_item_c[i] + annex_item_c[i][1] + annex_item_c[i][2]);

         }
     cout << f[n] << endl;//输出最终结果
     return 0;
}
posted @ 2021-11-12 17:27  卷卷人  阅读(38)  评论(0)    收藏  举报