问题描述
在一条街上有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的正整数。
请注意,以上都是给的第二天菜价的范围,第一天菜价可能会超过此范围。
整体上参考了https://blog.csdn.net/imotolove/article/details/82777819的思路,采用dfs搜索并优化剪枝,这里解释一下为什么利用isvis[400][400][400]进行优化是行之有效的,因为对于第i天来说,如果前一天pre和今天cur确定了,那么第三天也确定了(可能在此基础上加0,1,2),对后续的搜索结果也确定了,如果当前策略行不通(已经搜索过),那么自然就没必要往后面继续搜索了
其他一些博客采用了差分约束的解法,
dfs的解法及注释如下
#include <bits/stdc++.h>
using namespace std;
int day2[400], day1[400], n;
bool isfind = 0, isvis[400][400][400];
void dfs(int i, int cur, int pre){
if(isvis[i][cur][pre]) return;//当前状态已经搜索过,进行剪枝
isvis[i][cur][pre] = 1;
day1[i] = cur;
if(i == n){
if((day1[n - 1] + day1[n]) / 2 == day2[n]) isfind = 1;//核对最后一天
return;
}
int next = 3*day2[i] - pre - cur;//对第i天,如果该天cur,以及昨天pre确定,那么下一天有3种情况
for(int k = 0; k < 3; ++k){//0, 1, 2
if(next + k > 0 && !isfind){//注意next + k必须为正整数
dfs(i + 1, next + k, cur);
}
}
}
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; ++i){
scanf("%d", day2 + i);
}
for(int e = 1; e <= 2*day2[1]; ++e){
day1[1] = e;//第一天确定,那么第二天也能确定,有两种情况
dfs(2, 2*day2[1] - e, day1[1]);
if(!isfind) dfs(2, 2*day2[1] - e + 1, e);
else break;
}
for(int i = 1; i <= n; ++i){
printf("%d ", day1[i]);
}
return 0;
}