首页 > 其他分享 >dp题单vjudge 8.17

dp题单vjudge 8.17

时间:2024-08-17 20:53:48浏览次数:7  
标签:状态 int vjudge cin long 搜索 8.17 dp

HDU-1024 Max Sum Plus Plus

https://acm.hdu.edu.cn/showproblem.php?pid=1024

可以想到用dp过,但是无论时间和空间都不够,然后就不会了

https://www.cnblogs.com/wuwangchuxin0924/p/6546901.html

先写出转移方程,然后发现如果把其中一部分用其他的东西储存起来,就不需要重复寻找,直接使用就行了

3天的沉淀o( ̄┰ ̄*)ゞ

#include<bits/stdc++.h>
#define int long long
using namespace std;
int a[1000006]={0};
int b[1000006]={0};
int dp[1000006]={0};
const int inf=0x7ffffffff;
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int n,k;
    while(cin>>k>>n){
        for(int i=1;i<=n;++i){
            cin>>a[i];
        }
        for(int i=1;i<=n;++i){
            b[i]=dp[i]=0;
        }
        for(int i=1;i<=k;++i){
            b[i-1]=dp[i-1];
            for(int j=i;j<=n;++j){
                b[j]=max(b[j-1],dp[j]);
                dp[j]=dp[j-1]+a[j];
                dp[j]=max(dp[j],b[j-1]+a[j]);
            }
        }
        int ans=-inf;
        for(int i=k;i<=n;++i){
            ans=max(ans,dp[i]);
        }
        cout<<ans<<endl;
    }   
    return 0;
}

HDU-1047 Doing Homework

难死我了!查阅博客https://www.cnblogs.com/dilthey/p/7594497.html

开幕雷击,谢谢。


使用二进制,说实话在写这个题目的时候有乱想到,但是感觉更像是搜索因为时间复杂度就放弃,遂仔细梳理一下

一门课程完成的状态可以从未完成的状态转移过来,前一个未完成的状态是在之前得到过的最优解

和搜索有什么区别呢?当完成n门课的时候,实际上我已经把每一种顺序都跑了一次

好像回归到了dp最初的定义:把要重复使用的数据记录下来,下一次就不需要再算了

这道题的状态转移方程是好想的。


如果是直接搜索:对于一个规划好的顺序来看,假使我用solve函数去写,一定是一步步走下去的,这样就不好,但是dfs感觉应该是可以完成的,因为思维太朴素了,实际上搜索也一定不是把每一种顺序重新跑一遍,而是在当前的顺序下继续走下去而已。

算下时间复杂度,如果采取的措施是把选过的东西打上标记,不会重复搜索,那么相当于是 O(NN) 然后 N<15。其实是可以的吧

很不喜欢老题,因为很多数据的范围都没有给好,但是不做心里又难受,要消耗好多时间,尝试写一下dfs

因为题型知道了,接下来去找几道专门的状压dp做做就好,说实话要怎么保证字典序最小是一点想法都没有,还是太弱。但是评论区说数据给的很糟,不用考虑这一点,开心!ヾ(≧▽≦*)o

尝试写下,当做是锻炼代码能力了,现在是15:44 几点能完成呢?

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
int n;
map<int,string> p;
int a[20];//jie zhi
int b[20];//hao shi
int vis[20]={0};
int ans=0x7ffffffff;
vector<int> ansv;
vector<int> v;
void init(){
    ans=0x7ffffffff;
    p.clear();
    for(int i=1;i<=n;++i){
        vis[i]=0;
    }
    v.clear();
    ansv.clear();
}
void change(){
    ansv.clear();
    for(auto i:v){
        ansv.push_back(i);
    }
}
void dfs(int step,int now,int score){
    if(step==n) {
        if(score<ans){ change();ans=score; }
        return;
    }
    for(int i=1;i<=n;++i){
        if(vis[i]==1) continue;
        vis[i]=1;
        int t=now+b[i];
        int delt=t-a[i];
        if(delt<=0) delt=0;
        int ss=score+delt;
        v.push_back(i);
        dfs(step+1,t,ss);
        v.pop_back();
        vis[i]=0;
    }
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int time;
    cin>>time;
    while(time--){
        cin>>n;
        init();
        for(int i=1;i<=n;++i){
            string s;
            cin>>s;
            p[i]=s;
            cin>>a[i]>>b[i];
        }
        dfs(0,0,0);
        cout<<ans<<endl;
        for(auto i:ansv){
            cout<<p[i]<<endl;
        }
    }
    return 0;
}

出乎意料的快速的写完了。发现时间复杂度算错数字了,时间复杂度早就超了。看来是没有理解透彻状压dp

找些简单的状压做做

突然开窍,搜索和dp的区别就是

假如我要找从 n个科目-------转移到-------k个科目

如果是搜索,则是把每一种从 0-n的情况全都延续下去,一直到k个课程

相当于如果是从 n-k有m步,从0-n 有M 步,那样搜索总共走过的步数是 m*M

而dp来说我是在跑完 M的情况下,找出最优秀的情况然后转移到 k ,总的步数是 M+k

差不多就是这样的意思吧

非常聪明!o( ^ ▽ ^ )o

确实如同一篇博客所说 : 状压dp的特征就是 : 和搜索差不多 也是一种暴力

这一篇博客我印象非常深刻,以前曾分工动态规划,但是没有看懂

然后考虑如何保证字典序

假如我是从字典序小的一方开始遍历,那样我得到的第一个合适的最小值对应的方案就是字典序最小的方案

dp实现思路:

对于k节课程的状态,是由 这k个课程分别让每一个没有完成的状态转移过来,小的遍历然后取min值,大遍历的i节课程

关于转移到 选了k的状态,用一个tem=(1<<i)然后用k&tem即可,如果不为0则是这个书对于k来说是我想选的,然后把这一位给变为0,用异或即可,得到之前的状态

过程中我需要找到每一种状态的最优解,所以就是每一种状态都需要去跑一遍,为了能充分的传递,要从1的数目最少的开始。要怎么样才能把这些数字挑出来呢?

发现其实根本就不需要把这些数字给跳出来,如果是从1开始然后一直到(1<<n)就是朴素的遍历也就能保证需要的状态在之前就已经求得过了。

从二进制位上开始考虑 需要的位数上全是1的情况的数的大小其实就已经比所有能传递到这样的状态的数字更大了,所以只要从小往大遍历就完全足够!

很多代码实现的思路上的东西就是不太好讲,曾经也抱怨为什么很多博客的作者根本就不讲思路

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
int cnt=0;
int n;
map<int,string> p;
int a[100]={0};//jiezhi
int b[100]={0};//haoshi
int dp[40000]={0};
int tt[40000]={0};
vector<int> v[40000];//记录 字符串(顺序)
void change(int pre,int now,int add){
    v[now].clear();
    for(auto i:v[pre]){
        v[now].push_back(i);
    }
    v[now].push_back(add);
}
void init(){
    p.clear();
    for(int i=1;i<=(1ll<<n);++i){
        v[i].clear();
        dp[i]=0x7fffffff;
        tt[i]=0;
    }
}
signed main(){
    int timee;
    cin>>timee;
    while(timee--){
        cin>>n;
        init();
        int ans=0x7fffffff;
        for(int i=1;i<=n;++i){
            string s;
            cin>>s;
            p[i]=s;
            cin>>a[i]>>b[i];
        }
        int bb=(1ll<<n)-1;
        for(int i=1;i<=bb;i++){
            int tem=1;
            int cnt=0;
            while(tem<=i){
                cnt++;
                if((tem&i)!=0){
                    int x=i^tem;
                    tt[i]=tt[x]+b[cnt];
                    int y=tt[i]-a[cnt];
                    if(y<0) y=0;
                    int temm=y+dp[x];
                    if(dp[i]<temm) {tem<<=1;continue;}
                    else{
                        dp[i]=temm;
                        change(x,i,cnt);
                    }
                }
                tem<<=1;
            }
        }
        cout<<dp[(1<<n)-1]<<endl;
        for(auto i:v[(1<<n)-1]){
            cout<<p[i]<<endl;
        }
    }
    return 0;
}

一遍过!舒服了
写完了确实觉得比较简单

标签:状态,int,vjudge,cin,long,搜索,8.17,dp
From: https://www.cnblogs.com/z-zhi/p/18364955

相关文章

  • 8.17周总结
    本周学习的东西比较少,因为也要准备开学考试,本周将老师所留的PTA程序设计实验进行了结尾,并对CSS代码中的三个重要方面进行了学习,常规流,浮动。对于常规流,就是属于我们平常所写的一些代码,在这里我们了解了盒子的包含块,等于其父元素的内容盒;我学习了块盒,对于在块盒中,我知道了每个块盒......
  • 状压DP 前置 位运算
    功能1:判断一个数字\(x\)二进制下第\(i\)位是不是等于\(1\)if((1<<(i-1))&x)将1左移i-1位,相当于制造了一个只有第i位上是1,其他位上都是0的二进制数。然后与x做与运算如果结果\(>0\)说明x第i位上是1,反之是0功能2:将一个数字x二进制下第i位更改成1x=x|(1<<(i-1))......
  • 8.17
    ok 先来说一下近期变化  变胖了一点点 吃的太好了 and买了平板电脑今天刚到  然后今天闯了个红灯感觉非常不好spark环境搭建失败失败......................fuck尽管Spark相对于Hadoop而言具有较大优势,但Spark并不能完全替代Hadoop,Spark主要用于替......
  • 详细揭秘:区间 DP 小计
    状态设计例:沉玉谷\(n\)个有色小球排成一行,第\(i\)个小球颜色为\(c_i\),每次可以拿走连续一段颜色相同的小球,问有多少种方式取完所有小球。\(n\le50\)。考虑如何求一个区间的答案:枚举与\(l\)一同删去的最右的小球。不相交区间之间没有影响,所以还要多一维表示取了几次。......
  • 8.17日周记
    一、C语言学习1.pow函数用法:pow(底数,指数)例子:pow(x,2)=x²2.abs函数用法:abs(n)取n的绝对值3.strstr函数:搜索字符串1是否在字符串2中出现,若未搜索到,则返回NULL;若搜索到,则该函数返回第一次出现s2的地址。4.strcpy函数:用法:strcpy(字符串1,字符串2);strcpy函数将字符......
  • C240817D. 模拟赛:树上dp(以i为起点)+set操作
    C240817D.模拟赛比较显然的树上dp,但是维护set比较烦考场上其实自己是定义\(f[i]\)是以\(i\)结尾,然后这样的话单次更新根本做不到\(O(logN)\).反应实在是太迟钝了,考场想“如果有一种只更新一条链的dp就好了”结果完全没想到只需变成以\(i\)开头就行了.积累经验吧。......
  • 浅谈TCP协议、UDP协议
    一、介绍说明TCP(传输控制协议)面向连接:TCP在数据传输之前必须建立连接。这通过一个称为三次握手的过程来完成,确保连接的两端都准备好进行数据传输。可靠性:TCP提供可靠的数据传输,确保数据包正确无误地到达目的地。如果数据包在传输过程中丢失或损坏,TCP会重新发送这些数据包......
  • 换根dp
    大致步骤 换根dp大致步骤 方法一:(up数组)(1)g[i]以i为根的子树(不是整棵树),由孩子节点推过来(2)up[i]i节点往上走的最大属性(3)f[i]整棵树(不是子树)记录一些值 方法二:加减法(1)g[i]以i为根的子树(不是整棵树),由孩子节点推过来(2)f[i]整棵树(不是子树)记录一......
  • TCP/UDP网络聊天室
        本博客仅对网络聊天室项目进行分享,仅供学习讨论使用,欢迎大家讨论。UDP网络聊天室项目要求        利用UDP协议,实现一套聊天室软件。服务器端记录客户端的地址,客户端发送消息后,服务器群发给各个客户端软件,服务器也可以自己发送通知给所有客户端。  ......
  • 【网络】UDP回显服务器和客户端的构造,以及连接流程
    回显服务器(EchoServer)最简单的客户端服务器程序,不涉及到业务流程,只是对与API的用法做演示客户端发送什么样的请求,服务器就返回什么样的响应,没有任何业务逻辑,没有进行任何计算或者处理0.构造方法网络编程必须要使用网卡,就需要用到Socket对象创建一个DatagramS......