2021年5月10号-5月16号ACM学习日志

本周学习:加深背包问题,学习二分法

背包问题:
这周主要是在刷题,每天1到2个背包题,背包问题就那些套路,但题千变万化,有的题就是简单的01背包和完全背包,套下来就能对,到了多重背包,就要花些心思了。还有一个很重要,就是我们在看完题后,要辨别出这是个什么背包,他的数量有没有限制,查看限制信息。说实话,这周做的不怎么好,虽然背包问题比之前的dp简单一些,但这个有套路的感觉老是把我引偏,最后还是做不出来,可能是因为自己不够创新,做的题少,一看见题我就开始想着怎么把背包里的那几个套路放进去,可有的题不是那样的,他改变了很多,加了很多限制的条件,就像我们做普通的背包问题简化后用的是维数组,有的题可能需要用到两维,就是感觉做了很多题后,不能只限制于那些基本的套路,还是要具体问题具体分析,一开始做题的时候,基本的那些代码也没搞懂,就开始直接往上写。总之,不是只局限于那些基本的,要懂得创新。有一个题,老师上课讲的,基本的多重背包吧,但这个题的初始化很不一样。作业上的Y题,题目:https://vjudge.net/contest/436354#problem/Y
定义dp[i][j]为买了1~i 组费用为j 是得到的最大价值,这此之中,把dp[0][j]=0,其余定为-1,如果我们一开始把dp初始化为0,则当所有鞋子的价值都是0时,我们就无法区分是买不全那几款鞋子还是能买全但最大价值是0。
状态方程:dp[i][k] = max(dp[i][k], dp[i][k - p[i][j]] + v[i][j]); dp[i][k] = max(dp[i][k], dp[i - 1][k - p[i][j]] + v[i][j]);
代码:

#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <queue>
#include <stack>
#include <cmath>
using namespace std;
typedef long long  ll;
#define INF 0x7fffffff
#define t() cin>>t; while(t--)
#define mem(x) memset(x,INF,sizeof(x))
#define rep(m,n,h) for(int m=n;m<=h;m++)
#define cls(x) memset(x,0,sizeof(x))
const ll maxn=0x7fffffffffffffff;
const int N=20005;
const int mod=1e3+7;
int  z,ans,k,n,i,j,dp2[N][N],minn,t,e,f,m;
int temp,sum;
char st[5005];
int a[N],b[N];
map <char,int> sf;
vector<int> p[N], v[N];
int dp[105][N];

int main()
{
   // freopen("C:\\Users\\lenovo\\Desktop\\in.txt","r",stdin);
    std::ios::sync_with_stdio(false);
    while(cin>>n>>m>>t)
    {
        for(i = 0; i <= t; i++)
            {
            p[i].clear();
            v[i].clear();
        }
        int a, b, c;
        for( i = 0; i < n; ++i)
        {
            cin>>a>>b>>c;
            p[a].push_back(b);
            v[a].push_back(c);

        }
        for(int i = 0; i <= t; ++i)
            {
            for(int j = 0; j <= m; ++j)
            {
                if(i == 0)
                  dp[i][j] = 0;
                else dp[i][j] = -1;
            }
        }

        for(int i = 1; i <= t; ++i)
            {
            for(int j = 0; j < p[i].size(); ++j)
            {
                for(int k = m; k >= p[i][j]; --k)
                {
                    dp[i][k] = max(dp[i][k], dp[i][k - p[i][j]] + v[i][j]);
                    dp[i][k] = max(dp[i][k], dp[i - 1][k - p[i][j]] + v[i][j]);
                }
            }
        }
        if(dp[t][m] > 0)
            cout<<dp[t][m]<<endl;
        else cout<<"Impossible"<<endl;
    }
    return 0;
}

这几天做题,发现了一个问题,就是我习惯用自己写的一个对象,宏定义,头文件留下来,以后好直接用,但有的一些结构体,cmp函数之类的,还有一些对象,在我做题的时候可能会出现一些错误,就像我定义了两个不同类型的a,可能是因为我定义了太多变量了,有的就出错了,所以,之后我就把一些常用的变量对象保存下来,其他的在主函数里定义,这样也提高了容错率。

下面就是二分法了
基本思想就是你想查找一组数据中的一个值,我们就可以分成两块,如果s属于前面那一块,就舍弃后面,如果s属于后面那一块,我们就舍弃前面那一块,循环下来就找到了,但二分法有一个很重要的前提,就是这组数据必须有序,必须有序,必须有序,重要的事情说三遍。

while(high - low > 1.0e-6)
{
	 mid = (high + low)/2;
    if(Caculate(mid)<x)
        low=mid;
    else
        high=mid;
}

基础代码

下面是几个代码技巧
圆周率的表达

#define pi acos(-1)

快速读入

inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}

inline表示内联函数
普通函数有开栈和清栈,inline函数无开栈和清栈。

当执行开销(代码小)< 调用开销(开栈)时,建议用inline

当执行开销(代码小)> 调用开销(开栈)时,不建议使用inline

总结感想:上面在背包时写了一些,上面提到的就不再说了,这周看ppt的时间少了许多,其他科目的学习也是到了最后了,我不得不抽出时间巩固一下,为了期末的时候好复习。背包问题我感觉我学的不怎么好,可能是花的时间少了些,加上这几天有的题就是想不懂,为什么可以这样写,为什么要这样初始化。背包问题还是要再理解理解才行。二分法嘛,这个倒是挺容易理解的,就是在做题的时候是否能想到用二分法了,毕竟刚学,和自己在做题的时候用还是有区别的。这门课快结束了,更要打起精神来,我想着ACM不仅仅是一门课,课会结束,但我还是想在这方面有所发展。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值