【CodeForces】704 B. Ant Man「建议收藏」

【CodeForces】704 B. Ant Man

大家好,又见面了,我是全栈君。

【题目】B. Ant Man

【题意】给定n个人的xi,ai,bi,ci,di,起点为s,终点为e,移动:

In simpler words, jumping from i-th chair to j-th chair takes exactly:

  • |xi - xj| + ci + bj seconds if j < i.
  • |xi - xj| + di + aj seconds otherwise (j > i).

求中间经过所有点恰好一次的最小代价。

【算法】动态规划

【题解】很巧妙的DP状态设计。(这样类似哈密顿路径的问题不能从图论方面考虑,否则很容易变成NP问题)

将代价拆分到每个点:

向左,起c+x,落b-x

向右,起d-x,落a+x

那么对于前i个点,有效信息只有这i个点中缺少多少入边和缺少多少出边。先无视s(起点)和t(终点),那么缺入边数和缺出边数相等。

令f[i][j]表示前i个点中缺少j条入/出边的最小代价,缺少入边的本质是被往左,缺少出边的本质是往右。

对于f[i-1][j],有以下四种转移:

被往右+往右:j>0,f[i][j]=f[i-1][j]+a[i]+d[i](两个x[i]抵消)——减少一条出边,同时增加一条出边

往左+被往左:j>0,f[i][j]=f[i-1][j]+b[i]+c[i]——减少一条入边,同时增加一条入边

被往右+往左:j>0,f[i][j-1]=f[i-1][j]+a[i]+c[i]+2*x[i]——减少一条入边和一条出边

往右+被往左:f[i][j+1]=f[i-1][j]+b[i]+d[i]-2*x[i]——增加一条入边和一条出边

最终答案为f[n][0]。

接下来解决s和t的问题,实际上s和t才能代表一个完整的点,所以将s当成一个完整的点,不把t看作一个点。

先经过s:会多一条不该有的入边,所以只要避免第二个和第三个转移。

先经过t:会少一条该有的入边,所以只要在j=0时强制进行第二个转移。

最后在到达n之前和st均有或均无时,不能成环,强制f[i][0]=inf。

复杂度O(n^2)。

【CodeForces】704 B. Ant Man「建议收藏」
【CodeForces】704 B. Ant Man「建议收藏」

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll inf=1e16,maxn=5010;
ll f[maxn][maxn];
int n,s,t,x[maxn],a[maxn],b[maxn],c[maxn],d[maxn];
void m(ll &a,ll b){
    
    if(a>b)a=b;}
ll solve(){
    memset(f,0x3f,sizeof(f));
    int tot=0;f[0][0]=0;
    for(int i=1;i<=n;i++){
        for(int j=0;j<=i;j++)if(f[i-1][j]<inf){
            int S=j,T=S+tot;
            if(i==s){
                if(T)m(f[i][j],f[i-1][j]+c[i]+x[i]);
                m(f[i][j+1],f[i-1][j]+d[i]-x[i]);
            }
            else if(i==t){
                if(S)m(f[i][j-1],f[i-1][j]+a[i]+x[i]);
                m(f[i][j],f[i-1][j]+b[i]-x[i]);
            }
            else{
                if(S)m(f[i][j],f[i-1][j]+a[i]+d[i]);
                if(T)m(f[i][j],f[i-1][j]+b[i]+c[i]);
                if(S&&T)m(f[i][j-1],f[i-1][j]+a[i]+c[i]+2*x[i]);
                m(f[i][j+1],f[i-1][j]+b[i]+d[i]-2*x[i]);
            }
        }
        if(i==s)tot--;if(i==t)tot++;
        if(i!=n&&tot==0)f[i][0]=inf;
    }
    return f[n][0];
}
int main(){
    scanf("%d%d%d",&n,&s,&t);
    for(int i=1;i<=n;i++)scanf("%d",&x[i]);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)scanf("%d",&b[i]);
    for(int i=1;i<=n;i++)scanf("%d",&c[i]);
    for(int i=1;i<=n;i++)scanf("%d",&d[i]);
    printf("%lld",solve());
    return 0;
}

View Code

 

PS:我在这场比赛进行Virtual participation的时候,大力贪心出B……然后排名好高啊><。

至今无人能证明但AC了的贪心(似乎有人给反例):初始s-t,然后考虑一个一个点找最优位置插入。

转载于:https://www.cnblogs.com/onioncyc/p/8277875.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/107759.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • BigDecimal转String[通俗易懂]

    @特别鸣谢:BigDecimal转Stringpublicstaticvoidmain(String[]args){//浮点数的打印System.out.println(newBigDecimal(“10000000000”).toString());//普通的数字字符串System.out.pr…

    2022年4月4日
    5.8K
  • 8000—0004显示设备出现问题_错误0x8007005

    8000—0004显示设备出现问题_错误0x8007005关于COM类工厂80070005和8000401a错误分析及解决办法 问题描述:最近做一个web应用程序需要操作Excel文件,在开发环境下程序测试正常,部署到IIS后程序操作Excel文件,IIS报错,错误出现在创建Excel进程的语句,如下:Application myExcelApp= new ApplicationClass(); IIS提示信息如下:检索 COM 类

    2022年8月20日
    5
  • 制作镜像文件工具_镜像文件打开工具

    制作镜像文件工具_镜像文件打开工具openstack镜像制作要在openstack上创建虚拟机,必然要使用到虚拟机镜像。对于普通用户,可以使用已经创建好的虚拟机镜像。一般是操作系统官方构建并提供的。某些用户可以有自己独特的需求,需

    2022年8月4日
    2
  • Java 异常

    Java 异常

    2021年10月7日
    35
  • set集合的特点

    set集合的特点set集合的特点A:存入集合的顺序和取出集合的顺序不一致B:没有索引C:存入集合的元素没有重复set接口的实现类常用的有HashSet和TreeSet类。语法格式如下:Set<String>set1=newHashSet<String>();Set<String>set2=newTreeSe…

    2022年6月4日
    24
  • js原生拖拽的两种方法

    js原生拖拽的两种方法一.mousedown、mousemove和mouseup 拖着目标元素在页面任意位置如果要设置物体拖拽,那么必须使用三个事件,并且这三个事件的使用顺序不能颠倒。1.onmousedown:鼠标按下事件2.onmousemove:鼠标移动事件3.onmouseup:鼠标抬起事件重点:1、一定要绝对定位,脱离文档流才可以移动。2、绑定拖拽的元素,移动和鼠标松开后是对docu…

    2022年6月26日
    29

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号