IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> P1220 关路灯(区间DP+思维) -> 正文阅读

[数据结构与算法]P1220 关路灯(区间DP+思维)

题目链接:关路灯 - 洛谷

分析:这道题是一道比较好的区间DP题,首先从状态表示上来说,仅仅表示哪些灯亮着是不行的,还需要表示出当前所在的位置,一开始我以为这是一道状压DP,但是看了一眼数据范围发现用状压来解决肯定TLE,我们需要先想明白一个问题,就是有没有一种可能是在动态转移过程中最优答案的顺序包含一种i和j灯都已经被关掉但是i和j中间的灯还有没被关掉的?仔细想想发现这种情况是不可能存在的对吧,因为i和j灯都被关掉说明i和j之间的所有灯都被经过了,关灯又不需要时间,我们为什么不直接关掉呢?这也是这道题为什么可以用区间DP解决的原因。所以可以得到的一个结论是,在动态转移过程中被关掉的灯一定是连续的而不可能是间断的,所以我们就可以令f[i][j][0/1]表示i~j的灯已关闭且当前位置在i/j的时候最少的功耗,然后我们就可以进行动态转移了

下面我们来思考一下如何计算每次的功耗,这个比较简单就是(总的功率-已经灭掉的功率)*当前动态转移所需时间即可,我们可以令sum[i]表示前i个灯的功耗是多少,这样我们就可以o(1)求出连续区间的功耗,这样的话本道题就只剩下动态转移方程了,下面进行动态转移方程的讲解:

对于f[i][j][0]来说,我们枚举中间点k,这个肯定是由f[k][j][0/1]来更新的,因为f[i][j][0]表示最终位置在i,说明i这个位置的灯还没被关掉,所以不可能是由f[i][k][0/1]来进行更新,具体更新也比较简单,比如f[k][j][0]表示当前在k点,要向i点走,总地时间就是a[k]-a[i],这段时间里亮着的灯的功率为sum[n]-(sum[j]-sum[k-1]),因为k~j的灯都已经被关灭,所以动态转移方程就是这样的了,其他的状态也是一样的,我就不一个一个分析了,下面是动态转移方程代码:

f[i][j][0]=min(f[i][j][0],f[k][j][0]+(a[k]-a[i])*(sum[n]-(sum[j]-sum[k-1])));//当前位置在k且向i走
f[i][j][0]=min(f[i][j][0],f[k][j][1]+(a[j]-a[i])*(sum[n]-(sum[j]-sum[k-1])));//当前位置在j且向i走
f[i][j][1]=min(f[i][j][1],f[i][k][0]+(a[j]-a[i])*(sum[n]-(sum[k]-sum[i-1])));//当前位置在i且向j走
f[i][j][1]=min(f[i][j][1],f[i][k][1]+(a[j]-a[k])*(sum[n]-(sum[k]-sum[i-1])));//当前位置在k且向j走

至于初始化就比较简单了,一开始在的位置是pos,那么直接令f[pos][pos][0]=f[pos][pos][1]=0即可

下面是完整代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
typedef long long ll;
const int N=53;
ll f[N][N][2];//f[i][j][0/1]表示i~j的灯已关闭且当前位置在i/j的时候最少的功耗
ll a[N],sum[N];//sum[i]表示前i个灯1s的功耗 
int main()
{
	int n,pos;
	cin>>n>>pos;
	memset(f,0x3f,sizeof f);
	f[pos][pos][0]=f[pos][pos][1]=0;
	for(int i=1;i<=n;i++)
		scanf("%lld%lld",&a[i],&sum[i]),sum[i]+=sum[i-1];
	for(int len=2;len<=n;len++)
	for(int i=1;i+len-1<=n;i++)
	{
		int j=i+len-1;
		for(int k=i;k<=j;k++)
		{
			f[i][j][0]=min(f[i][j][0],f[k][j][0]+(a[k]-a[i])*(sum[n]-(sum[j]-sum[k-1])));//当前位置在k且向i走
			f[i][j][0]=min(f[i][j][0],f[k][j][1]+(a[j]-a[i])*(sum[n]-(sum[j]-sum[k-1])));//当前位置在j且向i走
			f[i][j][1]=min(f[i][j][1],f[i][k][0]+(a[j]-a[i])*(sum[n]-(sum[k]-sum[i-1])));//当前位置在i且向j走
			f[i][j][1]=min(f[i][j][1],f[i][k][1]+(a[j]-a[k])*(sum[n]-(sum[k]-sum[i-1])));//当前位置在k且向j走
		}
	}
	printf("%lld",min(f[1][n][0],f[1][n][1])); 
	return 0;
}

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-02-26 11:55:08  更:2022-02-26 11:56:31 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 16:55:51-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码