再卖菜(差分约束系统/dfs)

探讨一个有趣的数学问题,关于商店间菜价调整的规律。通过分析第二天的菜价,逆推第一天菜价的最小字典序解。涉及序列分析、算法优化及数据处理技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

时间限制:1.0s
内存限制:256.0MB
问题描述:

问题描述

  在一条街上有n个卖菜的商店,按1至n的顺序排成一排,这些商店都卖一种蔬菜。
  第一天,每个商店都自己定了一个正整数的价格。店主们希望自己的菜价和其他商店的一致,第二天,每一家商店都会根据他自己和相邻商店的价格调整自己的价格。具体的,每家商店都会将第二天的菜价设置为自己和相邻商店第一天菜价的平均值(用去尾法取整)。
  注意,编号为1的商店只有一个相邻的商店2,编号为n的商店只有一个相邻的商店n-1,其他编号为i的商店有两个相邻的商店i-1和i+1。
  给定第二天各个商店的菜价,可能存在不同的符合要求的第一天的菜价,请找到符合要求的第一天菜价中字典序最小的一种。
  字典序大小的定义:对于两个不同的价格序列(a1, a2, ..., an)和(b1, b2, b3, ..., bn),若存在i (i>=1), 使得ai<bi,且对于所有j<i,aj=bj,则认为第一个序列的字典序小于第二个序列。

输入格式

  输入的第一行包含一个整数n,表示商店的数量。
  第二行包含n个正整数,依次表示每个商店第二天的菜价。

输出格式

  输出一行,包含n个正整数,依次表示每个商店第一天的菜价。

样例输入

8
2 2 1 3 4 9 10 13

样例输出

2 2 2 1 6 5 16 10

数据规模和约定

  对于30%的评测用例,2<=n<=5,第二天每个商店的菜价为不超过10的正整数;
  对于60%的评测用例,2<=n<=20,第二天每个商店的菜价为不超过100的正整数;
  对于所有评测用例,2<=n<=300,第二天每个商店的菜价为不超过100的正整数。
  请注意,以上都是给的第二天菜价的范围,第一天菜价可能会超过此范围。

这道题递归很好拿分,看别人用了几步剪枝能100,厉害。我用python写的带剪枝的结果还超时,就算了。。。

正解是用差分约束系统转换成最短路问题,网上看完基础知识做这个题很顺利,不过python的spfa写的着实让我头疼。。

class node:
    pass

def add(u,v,w):
    global edg,head,cnt #python 在函数中要改变全局变量的值,需加
    ed = node()
    ed.v = v
    ed.w = w
    ed.next = head[u]
    edg.append(ed)
    head[u] = cnt 
    cnt+=1
    pass #这个gp pass语句毛用没有,本以为是在py里return空的意思
def spfa(s):
    queue = []
    queue.append(s)
    vis[s]=1
    for i in range(n): #抽象一个大源点,所有点入队,置dist为0,表示大源点联通所有si,边权为0,防止图不连通
        dist[i]=0
        rao[i]=1
    #print(queue)
    while not len(queue)==0:
        u = queue[0]
        queue.pop(0)
        #print(queue)
        #break
        vis[u] = 0
        k = head[u]
        while not k+1==0:
            v = edg[k].v
            if dist[v]<dist[u]+edg[k].w:
                dist[v]=dist[u]+edg[k].w
                if vis[v]==0:
                    vis[v]=1
                    queue.append(v)
                    rao[v]+=1
                    if rao[v]>n: #当进队次数大于n时,说明是负环,即无解 
                        return 0
            k=edg[k].next
    return 1
    
while True:
    try:
        cnt = 0
        rao = [0 for _ in range(3005)]
        vis = [0 for _ in range(3005)]
        dist = [0 for _ in range(3005)]
        edg = []
        head = [-1 for _ in range(12200)]
        p = [0 for _ in range(3005)]
        n = int(input())
        p[1:]=map(int,input().split())
        #print(p)
        for i in range(n-2): #3 0 /4 1/5 2....
            add(i,i+3,3*p[i+2])
            add(i+3,i,-(3*p[i+2]+2))
            #print(-(3*p[i+2]+2))

        add(2,0,-(2*p[1]+1))
        add(0,2,2*p[1])
        add(n,n-2,-(2*p[n]+1))
        add(n-2,n,2*p[n])
        #print(head)
        for i in range(n): #每个数都至少是1
            add(i,i+1,1)
        #print(1)
        if spfa(0):
            for i in range(1,n):
                print(dist[i]-dist[i-1],end=" ") 
            print(dist[n]-dist[n-1])
             
    except:
        break
 
 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值