【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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • CentOS 7中创软连接和scp命令

    CentOS 7中创软连接和scp命令(1)创建软连接 使用root用户操作语法:ln -s源路径软连接路径ln-s/home/hadoop/apps/zookeeper-3.4.10/usr/local/zookeeper(2)修改zookeeper软链接属主为hadoop 使用root用户操作chown-Rhadoop:hadoop/usr/local/zookeeper(3)s…

    2025年11月11日
    2
  • 配置druid数据源「建议收藏」

    配置druid数据源「建议收藏」配置druid数据源

    2022年4月25日
    45
  • js正则表达式语法大全_vb 正则表达式

    js正则表达式语法大全_vb 正则表达式 JavaScript正则表达式的用法正则表达式是一种可以用于模式匹配和替换的强大工具,在很多语言中都可以应用。JavaScript对正则表达式提供了很好的支持,Javascript中有一个正则表达式对象RegExp。该对象提供了大量的属性和方法来处理正则表达式,同时,String对象也提供了相关的方法来处理正则表达式,在Web应用中,经常使用正则表达式来验证用户输入的信息,例如在用

    2022年9月20日
    1
  • uniqueidentifier转换_unique函数哪个版本有

    uniqueidentifier转换_unique函数哪个版本有uniqueidentifier中文含义“唯一的标识符”。uniqueidentifier数据类型是16个字节的二进制值,应具有唯一性,必须与NEWID()函数配合使用。uniqueidentifier数据类型与identity自增不同,不会为插入的新行自动生成新的ID,新值由NEWID()函数指定。NEWID()函数值会生成全球唯一的标识,标识由网卡号和CPU时钟组成,如:6

    2025年10月1日
    7
  • 常用的快捷键 MAC IDEA (mac os X 10.5 )

    常用的快捷键 MAC IDEA (mac os X 10.5 )

    2021年5月12日
    242
  • Java遍历map集合的4中方式

    方法一通过Map.entrySet遍历key和value,在for-each循环中使用entries来遍历.推荐,尤其是容量大时这是最常见的并且在大多数情况下也是最可取的遍历方式。在键值都需要时使用。Map<Integer,Integer>map=newHashMap<Integer,Integer>();for(Map.Entry&l…

    2022年4月8日
    52

发表回复

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

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