问题 B: 烽火传递

题目描述

烽火台又称烽燧,是重要的军事防御设施,一般建在险要或交通要道上。一旦有敌情发生,白天燃烧柴草,通过浓烟表达信息;夜晚燃烧干柴,以火光传递军情,在某两座城市之间有 n  n 个烽火台,每个烽火台发出信号都有一定代价。为了使情报准确地传递,在连续 m  m 个烽火台中至少要有一个发出信号。请计算总共最少花费多少代价,才能使敌军来袭之时,情报能在这两座城市之间准确传递。

输入

第一行:两个整数 N,M N,M。其中N表示烽火台的个数, M  M 表示在连续 m  m 个烽火台中至少要有一个发出信号。接下来 N  N 行,每行一个数 Wi Wi,表示第i个烽火台发出信号所需代价。

输出

一行,表示答案。

样例输入

5 3

1

2

5

6

2

样例输出

4

提示

对于50%的数据,M≤N≤1,000  。 对于100%的数据,M≤N≤100,0000,Wi≤100。

思路:本题是dp加单调队列优化。

f[i]表示当第i个烽火台发出信号,前i个烽火台最少付出的代价。

f[i]=min{f[k]}(i-m<=k<=i-1)+w[i]

单调队列维护一单调递增区间,每次队首取出最小值。

代码

#include <bits/stdc++.h>

using namespace std;

int main()

{

       int n,m;

       int w[100001];

       //queue<int>q;

       int que[100001],head=0,tail=0;//队头、尾参数 ,队通过数组实现主要是由于queue对队尾的操作不是很方便

       int s[100001];//s数组用来存放每一次操作后的结果

       int ans=0x7f7f7f7f;//初始化为最大值

    scanf("%d%d",&n,&m);

    for(int i=1;i<=n;++i)

    scanf("%d",&w[i]);

    memset(s,-1,sizeof(s));//初始化为-1

    s[0]=0;

    que[0]=0;

    for(int i=1;i<=n;++i)

    {

        if(que[head]<i-m)

        head++;//将超出范围的队头删掉

        s[i]=s[que[head]]+w[i];//转移(用队头)

        while(head<=tail&&s[que[tail]]>s[i])

           tail--;//将不比它优的全部删掉

        que[++tail]=i;//将它加进队尾

    }

    for(int i=n-m+1;i<=n;i++)//对于后m组数据的结果取最小值

    ans=min(ans,s[i]);

    printf("%d\n",ans);

}

 

/* eslint-disable no-empty-pattern */ import React, { useEffect, useState, useCallback } from 'react' import { Button, Card, Form, Row, Col, message, Skeleton, DatePicker, } from 'antd' // 移除Select,新增UserSelect import { ProFormSelect, ProFormText, ProForm, ProFormDatePicker, } from '@ant-design/pro-components' import styled from '@emotion/styled' import NiceModal from '@ebay/nice-modal-react' import People from './setPeople' import Time from './setTime' import dayjs from 'dayjs' import { usePlanOne, useAddPlan, usePlanTrack, useEditPlan, } from '@/query/patrol-plan' import { useNavigate, useSearchParams } from 'react-router-dom' import { UserSelect } from '@repo/base' // 导入UserSelect组件 // 样式组件保持不变 const StyledTitle = styled('div')(({}) => ({ color: '#4683dd', background: '#f5f8fd', padding: '10px 20px', position: 'relative', ':before': { content: '""', width: '4px', height: '20px', background: '#3874cb', position: 'absolute', top: '50%', left: 0, transform: 'translateY(-50%)', }, })) const StyledBox = styled('div')(({}) => ({ border: '1px solid #ccc', borderRadius: '10px', padding: '30px', marginTop: '20px', })) const StyledButtonBox = styled('div')(({}) => ({ marginBottom: '30px', })) const StyledTable = styled('div')(({}) => ({ // border: '1px solid #f1f1f1', })) const StyledTr = styled('div')(({}) => ({ border: '1px solid #ccc', })) const StyledFirstTd = styled('div')(({}) => ({ width: '120px', background: '#d7d7d7', paddingTop: '10px', paddingBottom: '10px', paddingLeft: '10px', paddingRight: '10px', textAlign: 'center', color: '#4683dd', })) const StyledTd = styled('div')(({}) => ({ width: '120px', height: '54px', background: '#fff', paddingTop: '10px', paddingBottom: '10px', paddingLeft: '10px', paddingRight: '10px', textAlign: 'center', borderTop: '1px solid #f1f1f1', borderBottom: '1px solid #f1f1f1', color: '#4683dd', })) export default function Component() { const [searchParams] = useSearchParams() const id = searchParams.get('id')?.split(',')[0] const disabled = Boolean(Number(searchParams.get('disabled')?.split(',')[0])) const isCopy = searchParams.get('isCopy')?.split(',')[0] const actionRef = React.useRef() const [form] = ProForm.useForm() const [list, setList] = useState([]) const { data: formData, isLoading: isLoadingFormData } = usePlanOne({ id }) const [timeArr, setTimeArr] = useState([]) const [isDis, setIsDis] = useState(false) const [month, setMonth] = useState('') const { mutateAsync: runAdd } = useAddPlan({}) const { mutateAsync: update } = useEditPlan({}) const navigate = useNavigate() const { data: trackData, isLoading: isLoadingTrack } = usePlanTrack({}) const [trackOption, setTrack] = useState([]) const [selectedUsers, setSelectedUsers] = useState({}) // 存储已选用户信息(userId -> 用户详情) // 初始化路线数据 useEffect(() => { if (trackData) { setTrack( trackData.map(v => ({ label: v.name, value: v.id, })) ) } }, [trackData]) // 合并新旧数据逻辑(保持不变) const mergeWithExistingData = (newData, oldData) => { if (!oldData || oldData.length === 0) return newData return newData.map(group => group.map(newItem => { const oldItem = oldData .flatMap(g => g) .find(item => item.day === newItem.day) return oldItem ? { ...newItem, ...timeArr.reduce((acc, _, index) => { const personKey = `person${index + 1}` if (oldItem[personKey] !== undefined) acc[personKey] = oldItem[personKey] return acc }, {}), } : newItem }) ) } // 初始化日期列表(保持不变) const initDay = useCallback( (time = '') => { if (!time) { setList([]) return } try { const date = new Date(time) if (isNaN(date.getTime())) throw new Error('无效日期') const year = date.getFullYear() const monthNum = date.getMonth() const days = new Date(year, monthNum + 1, 0).getDate() const daysList = Array.from({ length: days }, (_, i) => i + 1) const newData = daysList.reduce((acc, day, index) => { if (index % 10 === 0) acc.push([]) acc[acc.length - 1].push({ day, ...timeArr.reduce((itemAcc, _, i) => { itemAcc[`person${i + 1}`] = '' return itemAcc }, {}), }) return acc }, []) setList(mergeWithExistingData(newData, list)) } catch (error) { console.error('日期初始化错误:', error) setList([]) } }, [timeArr, list, mergeWithExistingData] ) // 人员选择逻辑(保持不变:仅存储userId,显示依赖selectedUsers) const choosePeople = (groupIndex, itemIndex, personKey, value, userInfo) => { // 存储选中的用户详情(用于显示label) if (value && userInfo) { setSelectedUsers(prev => ({ ...prev, [value]: userInfo, // key: userId, value: 用户完整信息 })) } // 更新list中的人员ID setList(prevList => { return prevList.map((group, gIndex) => gIndex === groupIndex ? group.map((item, iIndex) => iIndex === itemIndex ? { ...item, [personKey]: value } : item ) : group ) }) } // 日期选择变化逻辑(保持不变) const handleDateChange = value => { const selectedMonth = dayjs(value).format('YYYY-MM') setMonth(selectedMonth) initDay(selectedMonth) } // 初始化详情数据(适配UserSelect:存储用户详情到selectedUsers) useEffect(() => { if (!formData || isLoadingFormData) return // 重置状态 setTimeArr([]) setList([]) setSelectedUsers({}) // 重置已选用户 // 表单字段初始化 form.setFieldValue('trackId', formData?.trackId) form.setFieldValue('planMonth', dayjs(formData.planMonth, 'YYYY-MM')) form.setFieldValue('remark', formData?.remark) if (formData.bizPatrolPlanDetailList?.length > 0) { // 提取时间列表 const uniqueTimes = [ ...new Set( formData.bizPatrolPlanDetailList.map(item => item.planDetailTime.split(' ')[1].slice(0, 5) ) ), ].sort() setTimeArr(uniqueTimes.map(time => ({ time }))) // 初始化月份和日期列表 const planMonth = formData.planMonth setMonth(planMonth) initDay(planMonth) // 判断禁用状态 const currentMonth = dayjs().format('YYYY-MM') const isDisabled = new Date(currentMonth).getTime() >= new Date(planMonth).getTime() if (isCopy != 1) { setIsDis(isDisabled) } // 初始化已选用户(从formData提取用户详情) const initSelectedUsers = {} formData.bizPatrolPlanDetailList.forEach(item => { if (item.userId && item.userName) { initSelectedUsers[item.userId] = { id: item.userId, realName: item.userName, ...item, // 保留其他用户信息 } } }) setSelectedUsers(initSelectedUsers) // 填充人员配置到list setTimeout(() => { const uniqueTimesMap = uniqueTimes.reduce((acc, time, index) => { acc[time] = index return acc }, {}) const personConfigMap = {} formData.bizPatrolPlanDetailList.forEach(item => { const [datePart, timePart] = item.planDetailTime.split(' ') const day = parseInt(datePart.split('-')[2]) const time = timePart.slice(0, 5) const timeIndex = uniqueTimesMap[time] if (timeIndex !== -1) { personConfigMap[day] = { ...personConfigMap[day], [`person${timeIndex + 1}`]: item.userId, } } }) setList(prevList => prevList.map(group => group.map(item => ({ ...item, ...personConfigMap[item.day], })) ) ) }, 100) } }, [formData, isLoadingFormData, form, id, isCopy, initDay]) // timeArr更新后重新初始化日期列表(保持不变) useEffect(() => { if (month && timeArr.length > 0) { initDay(month) } }, [month, timeArr, initDay]) const labelCol = { span: 4 } // 初次加载显示骨架屏(保持不变) if (isLoadingFormData || isLoadingTrack) { return ( <Card style={{ paddingTop: '24px', minHeight: '500px' }}> <Skeleton active paragraph={{ rows: 5 }} /> </Card> ) } return ( <Card style={{ paddingTop: '24px', }} > <ProForm layout="horizontal" form={form} onFinish={async values => { values.planMonth = dayjs(values.planMonth).format('YYYY-MM') // 构建提交数据(保持不变:仅传递userId) const scheduleData = list.flatMap(group => group.flatMap(item => timeArr.map((timeItem, i) => ({ userId: item[`person${i + 1}`], // 仅传递userId planDetailTime: `${values.planMonth}-${String(item.day).padStart(2, '0')} ${timeItem.time}:00`, })) ) ) try { if (id) { await (isCopy === '1' ? runAdd : update)({ ...values, bizPatrolPlanDetailList: scheduleData, patrolTime: timeArr.map(v => v.time).join(','), id: isCopy === '1' ? undefined : id, }) message.success('修改成功!') } else { await runAdd({ ...values, bizPatrolPlanDetailList: scheduleData, patrolTime: timeArr.map(v => v.time).join(','), }) message.success('添加成功!') } navigate(-1) } catch (error) { message.error('操作失败,请重试') console.error('保存失败:', error) } }} submitter={false} actionRef={actionRef} > {/* 路线名称、计划月份、备注表单(保持不变) */} <Row> <Col span={8}> <ProFormSelect label="路线名称" disabled={disabled || isDis} readonly={disabled} name="trackId" required options={trackOption} formItemProps={{ labelCol }} /> </Col> <Col span={8} offset={2}> {disabled ? ( <ProFormDatePicker fieldProps={{ picker: 'month', format: 'YYYY-MM', }} name="planMonth" label="计划月份" readonly /> ) : ( <Form.Item label="计划月份" name="planMonth" required labelCol={{ span: 4 }} > <DatePicker onChange={handleDateChange} picker="month" disabled={disabled || isDis} placeholder="请选择计划月份" /> </Form.Item> )} </Col> </Row> <Row> <Col span={8}> <ProFormText label="备注" name="remark" readonly={disabled} formItemProps={{ labelCol }} /> </Col> </Row> {/* 计划安排表格(核心:Select替换为UserSelect) */} <StyledTitle>计划安排</StyledTitle> <StyledBox> <StyledButtonBox> {disabled ? ( <> <Button type="text" disabled> 配置时间 </Button> <Button type="text" disabled> 配置人员 </Button> </> ) : ( <> <Button disabled={disabled} size="middle" onClick={() => { if (!month) { message.warning('请选择月份!') return } NiceModal.show(Time, { id: '', timeArr, onOk: value => setTimeArr(value.map(time => ({ time }))), }) }} > 配置时间 </Button> <Button disabled={disabled} type="default" style={{ marginLeft: '20px' }} onClick={() => { if (timeArr.length === 0) { message.warning('请先配置时间!') return } NiceModal.show(People, { id: '', timeArr, month, onOk: ({ dateRange, personConfig }) => { const [startDay, endDay] = dateRange.map(str => parseInt(str.split('-')[2]) ) // 1. 存储配置的用户详情到selectedUsers const newSelectedUsers = { ...selectedUsers } personConfig.forEach(config => { if (config.person && config.userInfo) { newSelectedUsers[config.person] = config.userInfo } }) setSelectedUsers(newSelectedUsers) // 2. 更新list中的人员ID setList(prevList => prevList.map(group => group.map(item => item.day >= startDay && item.day <= endDay ? { ...item, ...personConfig.reduce((acc, config) => { const timeIndex = timeArr.findIndex( t => t.time === config.time ) if (timeIndex !== -1 && config.person) { acc[`person${timeIndex + 1}`] = config.person } return acc }, {}), } : item ) ) ) }, }) }} > 配置人员 </Button> </> )} </StyledButtonBox> <StyledTable> {list.length === 0 ? ( <div style={{ textAlign: 'center', padding: '50px' }}> {month ? '暂无计划安排,请配置时间和人员' : '请先选择计划月份'} </div> ) : ( list.map((v, index) => ( <div style={{ display: 'flex' }} key={index}> <StyledTr> <StyledFirstTd>时间</StyledFirstTd> {timeArr.map((timeItem, timeIndex) => ( <StyledTd key={timeIndex}>{timeItem.time}</StyledTd> ))} </StyledTr> {v.map((n, Nindex) => ( <StyledTr key={Nindex}> <StyledFirstTd>{n.day}日</StyledFirstTd> {timeArr.map((timeItem, i) => { const personId = n[`person${i + 1}`] // 从selectedUsers获取用户label(适配UserSelect选择结果) const currentLabel = personId ? selectedUsers[personId]?.realName || '未安排' : '未安排' return ( <StyledTd key={i}> {disabled ? ( // 禁用时显示人员名称 <div style={{ color: '#333' }}> {currentLabel} </div> ) : ( // 启用时显示UserSelect(替换原Select) <UserSelect style={{ width: '100px' }} showSearch allowClear placeholder="请选择人员" disabled={disabled} // UserSelect选择后触发:传递userId和完整用户信息 onSelect={(value, option) => { choosePeople( index, Nindex, `person${i + 1}`, value, // userId option // 完整用户信息(含realName、id等) ) }} // 初始值:仅传递userId(UserSelect内部会匹配显示label) value={personId || undefined} /> )} </StyledTd> ) })} </StyledTr> ))} </div> )) )} </StyledTable> </StyledBox> {/* 取消/确定按钮(保持不变) */} <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: '20px', }} > <Button type="default" htmlType="reset" onClick={() => { navigate(-1) }} > 取消 </Button> {!disabled ? ( <Button type="primary" style={{ marginLeft: '20px', }} htmlType="submit" > 确定 </Button> ) : ( '' )} </div> </ProForm> </Card> ) } 点击设置人员,onOk返回的数据格式为0 : label : "曾军" person : "b04fa22bc35243da803a9cacb9873b37" time : "08:00" userInfo : account : "zengj" email : "zengj@fiberhome.com" employeeNo : "0210990847" id : "b04fa22bc35243da803a9cacb9873b37" myAccountNonExpired : true myAccountNonLocked : "true" myAccountNonLocked_dicName : "未锁定" myCredentialsNonExpired : true myEnabled : true orgId : "32a63cce0b884ebd94f9390d1f516677" orgName : "高管" realName : "曾军" status : "active" status_dicName : "启用" treeLevelId : "8d8abd2050ed468d98681f98246d0107/4953b174581c471b894ac8eedf36e838/32a63cce0b884ebd94f9390d1f516677" treeLevelName : "烽火科技集团/烽火通信科技股份有限公司/高管" username : "zengj,处理一下页面回显的问题
最新发布
10-24
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值