山东大学计算机科学与技术学院程序设计思维与实践作业 week14-动态规划(4)

这篇具有很好参考价值的文章主要介绍了山东大学计算机科学与技术学院程序设计思维与实践作业 week14-动态规划(4)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

山东大学计算机科学与技术学院程序设计思维与实践作业
山大程序设计思维与实践作业
sdu程序设计思维与实践
山东大学程序设计思维实践作业H14
山大程序设计思维实践作业H14
山东大学程序设计思维与实践
week14-动态规划(4)
相关资料:GitHub

A : 直径数量问题

题目描述
给出一棵树,求树的直径及其数量(最长简单路径的长度和数量)。

输入格式
第一行一个整数 n , 0≤n≤10^5,
接下来有 n−1 行,每行 a,b 代表 a 到第 b 有一条长度为 1 的边。
1≤a,b≤n

输出格式
输出两个数,分别表示树的直径和数量。

样例输入
5
5 1
1 2
2 3
2 4
样例输出
3 2

#include <bits/stdc++.h>
using namespace std;

const int maximumnum = 1e5 + 11;
int diam[maximumnum], far[maximumnum], countd[maximumnum], countf[maximumnum];
vector<int> edge[maximumnum];

void dfs(int x, int f){
    countf[x] = 1; // 最远路径数为1
    // 遍历x的所有除了父节点的邻接点,求最远路的个数
    for(auto &i : edge[x]){
        if(i == f) continue; // 父节点不在子树中
        dfs(i,x); // 对该子树求结果
        // 如果从这个子节点走到的更远,直接更新为子树的这条最远路的个数
        if(far[i] + 1 > far[x]){
            far[x] = far[i] + 1;
            countf[x] = countf[i];
        }
        // 若又找到一条和当前最远路一样长的字节点
        // 就将最远路的长度加上这个子节点带来的最远路径数
        else if(far[i] + 1 == far[x])
            countf[x] += countf[i];
    }

    // 情况1: 由根节点到叶子的一条路径
    diam[x] = far[x];
    countd[x] = countf[x];

    // 情况2: 经过根节点的一条路径

    int Max = 0,subMax = 0;
    int cntn = 0; // 直径经过根节点的方案个数
    if(!((f == -1 && edge[x].size() < 2) || (f != -1 && edge[x].size() < 3))){

        // 求最远距离和第二远的距离
        for(auto &i : edge[x]){
            if(i == f) continue;
            // 若这条子树的最远距离+1比当前第二远的路径还远,更新
            if(far[i] + 1 > subMax) {
                subMax = far[i] + 1;
                // 保证最远的路径比第二远的路径要远
                if(subMax > Max)
                    swap(subMax,Max);
            }
        }

        // 处理
        // 若最远路径和第二远路径大小相同
        if(subMax == Max){
            int cnt = 0;// 记录最大值的数量
            for(auto &i :edge[x]){
                if(i == f) continue;
                // 因为要随机选择两条最远路,需要将其中一条路是该节点的最远路的情况
                // 即用当前的最大值数 * 当前子节点的最远路情况数
                if(far[i] + 1 == subMax){
                    cntn += cnt * countf[i];
                    cnt += countf[i];
                }
            }
        }
        // 若最远路径和第二远路径大小不同
        else{
            int cntMax = 0, cntSubMax = 0;
            for(auto &i :edge[x]){
                if(i == f) continue;
                // 更新最远路Max的情况数
                if(far[i] + 1 == Max)
                    cntMax += countf[i];
                // 更新第二最远路subMax的情况数
                else if(far[i] + 1 == subMax)
                    cntSubMax += countf[i];
            }
            // 结果为两种情况的乘积
            cntn = cntMax * cntSubMax;
        }
    }

    // 情况3: 不经过根节点的一条路径
    for(auto &i :edge[x]){
        // 找到所有以子节点为根的树的直径的最大值即可
        if(i == f) continue;
        // 若该子节点为根的直径大于当前的最大值,就将结果更新为当前子树的直径
        if(diam[i] > diam[x]){
            diam[x] = diam[i];
            countd[x] = countd[i];
        }
        // 若该子节点为根的直径等于当前的最大值,就将结果加上为当前子树的直径情况数
        else if(diam[i] == diam[x])
            countd[x] += countd[i];
    }
    // 比较选择出三种情况中最大的情况
    if(Max + subMax > diam[x]) {
        diam[x] = Max + subMax;
        countd[x] = cntn;
    }
    // 若不同情况中有相同大小的直径,则把各种情况求和
    else if(Max + subMax == diam[x])
        countd[x] += cntn;

}
int main(){
    int n;
    cin >> n;
    int u ,v;
    // 插入边
    while(--n){
        cin >> u >> v;
        edge[u].push_back(v);
        edge[v].push_back(u);
    }
    // dfs求直径
    dfs(1,-1);
    // 输出直径和数量
    cout << diam[1] << " " << countd[1] << endl;
    return 0;
}

B : 城市规划

题目描述
有一座城市,城市中有 N 个公交站,公交站之间通过 N−1 条道路连接,每条道路有相应的长度。保证所有公交站两两之间能够通过唯一的通路互相达到。
两个公交站之间路径长度定义为两个公交站之间路径上所有边的边权和。
现在要对城市进行规划,将其中 M 个公交站定为“重要的”。
现在想从中选出 K 个节点,使得这 K 个公交站两两之间路径长度总和最小。输出路径长度总和即可(节点编号从 1 开始)。

输入格式
第 1 行包含三个正整数 N,M 和 K 分别表示树的节点数,重要的节点数,需要选出的节点数。
第 2 行包含 M 个正整数,表示 M 个重要的节点的节点编号。
接下来 N−1 行,每行包含三个正整数 a,b,c,表示编号为 a 的节点与编号为 b 的节点之间有一条权值为 c 的无向边。每行中相邻两个数之间用一个空格分隔。

输出格式
输出只有一行,包含一个整数表示路径长度总和的最小值。

样例输入
5 3 2
1 3 5
1 2 4
1 3 5
1 4 3
4 5 1
样例输出
4
样例解释
山东大学计算机科学与技术学院程序设计思维与实践作业 week14-动态规划(4)

样例中的树如上图所示。
重要的节点标号为 1, 3, 5,从中选出两个点,有三种方案:
方案 1: 1, 3 之间路径长度为 5
方案 2: 1, 5 之间路径长度为 4
方案 3: 3, 5 之间路径长度为 9

#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef long double ld;
const int N = 5e4+7;
tree<ll,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update> tr;
ll gcd(ll a, ll b){ return a == 0 ? b : gcd(b % a, a); }
ll exgcd(ll a,ll b,ll&x,ll&y){if(b==0){x=1,y=0;return a;}else{ll r=exgcd(b,a%b,x,y),t=x;x=y;y=t-a/b*x;return r;}}//注意x,y一定为ll

int a[N],head[N],cnt=1,vis[N];
ll dp[N][107], inf = 1e15;
struct edge{
    int f,t,n;
    ll w;
}g[N*2];
int n,m,k,x;
void add(int f,int t,ll w){
    g[cnt].n = head[f];
    g[cnt].t = t;
    g[cnt].w = w;
    head[f] = cnt++;
}
void dfs(int u,int fa){
    dp[u][0] = 0;
    if(vis[u]) dp[u][1] = 0;
    for(int i=head[u];i;i=g[i].n){
        int to = g[i].t;
        if(to==fa) continue;
        dfs(to,u);
        for(int j=k;j>=1;j--){
            for(int w=j;w>=0;w--){
                dp[u][j] = min(dp[u][j],dp[u][j-w]+dp[to][w]+g[i].w*w*(k-w));
            }
        }
    }
}
int main(){
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++)
        for(int j=0;j<=k;j++)
            dp[i][j] = inf;
    for(int i=1;i<=m;i++) cin>>x, vis[x]=1;
    for(int i=0;i<n-1;i++){
        int f,t,w;
        cin>>f>>t>>w;
        add(f,t,w), add(t,f,w);
    }
    dfs(1,0);
    cout<<dp[1][k];
}

##C : 最大区间和

题目描述
输入一个长度为 n 的整数序列 a,从中找出一段不超过 m 的连续子序列(区间),使得这个序列的和最大。选出的区间可以为空。
n≤106,m≤n,−109≤ai≤109

输入描述
第一行两个数 n,m,第二行 n 个整数 ai 表示这个数列。

输出描述
一个整数表示答案。

样例输入
6 3
1 -3 5 1 -2 3
样例输出
6

#include <bits/stdc++.h>
using namespace std;
const int maximumn = 1e6+10;
long long a[maximumn];       /*a数组存区间*/
long long sum[maximumn];    /*sum记录前缀和*/
long long result;
deque<long long> q;//双端队列存下标
int main(){
    int n,m;
    cin>>n>>m;
    for(int i = 1; i <= n; i++) {
        cin>>a[i];
        sum[i] = sum[i-1] + a[i];
    }
    q.push_back(0);
    /*使用一个单调队列维护最小值*/
    for(int i = 1; i <= n; i++){
        /*保证是最小的前缀和*/
        while(!q.empty() && sum[q.back()] > sum[i])
            q.pop_back();
        q.push_back(i);
        /*如果超过了m的范围,进行去除*/
        while(!q.empty() && i - m > q.front())
            q.pop_front();
        
        result = max(result,sum[i] - sum[q.front()]);
    }
    cout<<result<<endl;
    return 0;
}

D : 帝国大厦

题目描述
帝国大厦共有 n 层,LZH 初始时在第 a 层上。
帝国大厦有一个秘密实验室,在第 b 层,这个实验室非常特别,对 LZH 具有约束作用,即若 LZH 当前处于 x 层,当他下一步想到达 y 层时,必须满足 ∣x−y∣<∣x−b∣,而且由于实验室是不对外开放的,电梯无法停留在第 b 层。
LZH 想做一次旅行,即他想按 k 次电梯,他想知道不同的旅行方案个数有多少个。
两个旅行方案不同当前仅当存在某一次按下电梯后停留的楼层不同。

输入格式
一行 4 个数 n,a,b,k。

输出格式
一个数表示答案,由于答案较大,将答案对 109+7 取模后输出。

数据范围与子任务
对于 40% 的数据 n,k≤500。
对于 80% 的数据 n,k≤2000。
对于 100% 的数据 n,k≤5000,1≤a,b≤n,a=b。

测试样例
样例 1
输入:
5 2 4 1
输出:
2
样例 2
输入:
5 2 4 2
输出:
2
样例 3
输入:
5 3 4 1
输出:
0文章来源地址https://www.toymoban.com/news/detail-489452.html

#include <bits/stdc++.h>
using namespace std;
const long long mod = 1e9 + 7;
const int maximumnum = 5005;
int n,a,b,k;
long long res;
//状态定义
long long dp[maximumnum]; //dp[i]表示到按k次后到第i层的方案书
long long sum[maximumnum]; //sum[i]维护dp[i]前缀和

//使用前缀和,使得不TLE

int main(){
    cin>>n>>a>>b>>k;
    dp[a]  = 1;
    for(int i = a; i <= n; i++)
        sum[i] = 1;
    for(int i = 1; i <= k; i++){  //按下k次电梯
        for(int j = 1; j <= n; j++){  //遍历每一层
            //如果j>b那么dp[j]为从(b+y)/2到n的和(该区间是所有能到达该层的区间)并且去掉本身
            if(j > b) {
                dp[j] = sum[n] - sum[(j+b)>>1] - sum[j] + sum[j-1];
                if(dp[j]> mod)
                    dp[j] =  dp[j]%mod;
                else if(dp[j]< 0)
                    dp[j] =  mod + dp[j];
            }
            //如果j<b,dp【j】为从0到(b+y)/2的和,并且去掉本身
            if(j < b){
                dp[j] = sum[(j+b-1) >> 1] - sum[j] + sum[j-1];
                if(dp[j]> mod)
                    dp[j] =  dp[j]%mod;
                else if(dp[j]< 0)
                    dp[j] =  mod + dp[j];
            }
        }
        for (int j = 1; j <= n; j++)
            sum[j] = (sum[j-1] + dp[j]) % mod;
    }

    sum[n] = sum[n] % mod;
    cout << sum[n] << endl;
    return 0;
}

到了这里,关于山东大学计算机科学与技术学院程序设计思维与实践作业 week14-动态规划(4)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 山东大学众智科学与网络化产业复习笔记

    写在前面:鹿男神yyds,讲课诙谐有趣,条理清晰,给分可冲,总而言之,众智可冲,题主94,12/160,本文是复习时的总结,希望学弟学妹95+ 图 = 事物(节点) + 联系(边) 同构:图的画法不同,结构上相同,两图同构意味着可以找到一组对应的点,其关系也一致。 邻接矩阵

    2024年01月23日
    浏览(33)
  • 山东大学软件学院2022-2023数据科学导论知识点整理【软工大数据课组】

    CSDN的排版能力有限,因此留pdf版本,祝大伙全部95+,呼呼 山东大学软件学院2022-2023数据科学导论知识点整理【软工大数据课组】-统计分析文档类资源-CSDN文库 总体上是概论部分,可能考的也就名词解释了,总结如下: 什么是大数据,大数据的界限,4V? 大数据是一种数据规

    2024年02月06日
    浏览(41)
  • 山东大学计算机网络期末

    内容仅供参考。如有错误之处,敬请指正! 第一章 概述 第二章 物理层 第三章 数据链路层 第四章 介质访问子层 第五章 网络层 第六章 传输层 第七章 应用层 1.基本概念 计算机网络定义: 表示一组通过单一技术相互连接起来的自主计算机集合。 分布式系统: 是建立在网络

    2024年02月03日
    浏览(44)
  • 山东大学软件学院2022软件测试技术期末试题回忆

    前言:本篇博客记录2022大三下软件测试技术期末试题。 复习资料:山东大学软件学院软件测试技术期末复习知识总结 一(15\\\') 1、软件缺陷 2、系统测试 3、回归测试 4、软件国际化 5、测试自动化 二(20\\\') 1、单元测试和代码调试 2、比较集成测试的不同模式,简述集成测试

    2024年02月09日
    浏览(47)
  • 山东大学软件学院计算机网络期末考试考点

    单播 :只有一个发送方和一个接收方的点到点传输。 组播 :将一个数据包发送给一组机器,即所有机器的一个子集。 广播 :将一个数据包发送给所有的目标机器。 面向连接的服务 :按照电话系统建模,服务用户首先必须建立一个连接,然后使用该连接传输数据,最后释放连接。

    2024年02月03日
    浏览(41)
  • 2022山东大学软件学院区块链原理与技术期末考试(回忆版)

    这是限选课孔连菊老师的区块链,还是要复习重点,考试内容不多,有点超出想象,和往年题内容形式还是有点出入,众所周知,孔老师绝不透露和考试有关的半点内容。。。。分享给学弟学妹们涨点人品。 题量不大甚至可以说是非常小,但是个人答的确实不咋样,复习半天

    2024年02月11日
    浏览(58)
  • 山东专升本计算机第六章-数据库技术

    数据库技术 SQL数据库与NOSQL数据库的区别 数据库管理系统 考点 6 数据库管理系统的组成和功能 组成 • 模式翻译 • 应用程序的翻译 • 交互式查询 • 数据的组织和存取 • 事务运行管理 • 数据库的维护 功能 • 数据定义功能 • 数据存取功能 • 数据库运行管理能力 • 数

    2024年02月05日
    浏览(32)
  • 山东专升本计算机第十一章-新一代信息技术

    新一代信息技术 物联网 概念 物联网就是物物相连的互联网,其核心和基础仍然是互联网 计算机,互联网之后信息产业发展的第三次浪潮 推入人类进入智能时代,又称物联时代 三大特征 全面感知 可靠传递 智能处理 • 物联网的最核心 技术架构 感知层 网络层 服务管理层(

    2024年02月01日
    浏览(35)
  • 小白怎么系统的自学计算机科学和黑客技术?

    我把csdn上有关自学网络安全、零基础入门网络安全的回答大致都浏览了一遍,最大的感受就是“太复杂”,新手看了之后只会更迷茫,还是不知道如何去做,所以站在新手的角度去写回答,应该把回答写的简单易懂,“傻瓜式”的一步步告诉他们应该怎么去做 在文章的后半

    2023年04月14日
    浏览(39)
  • 山东大学增强现实实验四

    注意:本人尚处在opencv的入门学习阶段,本博客仅为个人学习笔记见解,如有不当,欢迎指出 (实验/理论)平面标志物的视觉跟踪,要求: 选择一个标志物,可以是人工标志物,也可以是自然标志物;实现和实验二相同的效果。 用手机或摄像头拍摄标志物的影像,建议读取视

    2024年02月08日
    浏览(64)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包