描述
Farmer John 在给他编号为 1…N 的 N 头奶牛排队拍照(2≤N≤103)。FJ 一开始计划从左向右数第 i 个位置排编号为 ai 的奶牛,他在一张纸上写下了排列 a1,a2,…,aN。不幸的是,这张纸刚刚被 Farmer Nhoj 偷走了!
幸好 FJ 仍然有机会恢复他之前写下的排列。在这张纸被偷走之前,Bessie 记录了序列 b1,b2,…,bN-1,对于每一个1≤ii=ai+ai+1。
基于 Bessie 的信息,帮助 FJ 恢复可以产生序列 b 的“字典序最小”的排列 a。排列 x 字典序小于排列 y,如果对于某个 j,对于所有 xi=yi,且有 xj<yj(换句话说,这两个排列到某个位置之前都相同,在这个位置上 x 小于 y)。保证存在至少一个满足条件的 a。
测试点性质:
• 测试点 2-4 满足 N≤8。
• 测试点 5-10 没有额外限制。
输入
输入的第一行包含一个整数 N。
第二行包含 N-1 个空格分隔的整数 b1,b2,…,bN-1。
输出
输出一行,包含 N 个空格分隔的整数 a1,a2,…,aN。
样例输入
5
4 6 7 6
样例输出
3 1 5 2 4
提示
a 能够产生 b,因为 3+1=4,1+5=6,5+2=7,2+4=6。
分析
解法一、暴力枚举(真能过)
解法二、set+枚举
公式变形
b2=a2+a3 b3=a3+a4
b3-b2=a4-a2 a2–>已知 b2-b1=a3-a1–> a3=b2-b1+a1
a数组里不能有重复的元素,那就用set容器存储某些结果
解法三、dfs
代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5+10;
int n;
int a[N],b[N],s[N];
int main()
{
cin>>n;
bool flag=false;
for (int i = 0; i < n-1; i ++ )cin>>b[i];
for (int i = 1; i <= n; i ++ )
{
memset(s, 0, sizeof s);
a[0]=i;//从1开始枚举
s[i]=1;//标记
for (int j = 0; j < n-1; j ++ )
{
int x=b[j]-a[j];//a[j+1]的可能值
if(x<=0||s[x])break;
else
{
a[j+1]=x;//赋值
s[x]++;
if(j+1==n-1)//a数组存在,因为是从小开始枚举,此时一定是字典序最小
{
for (int i = 0; i < n; i ++ )
cout<<a[i]<<' ';
return 0;
}
}
}
}
return 0;
}
一位大佬的解法
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1010;
int n , a[N] , b[N];
bool st[N];
bool dfs(int idx){ //idx为当前枚举的位置
if(idx==n)return true;//第一次出来的就是字典序最小的了
for (int i = 1; i <= b[idx]; i ++ ) //枚举a[idx]可能的大小
if(!st[i] && a[idx-1]+i==b[idx]){ //i这个数字没有出现过 和 前面确定的数字和目前数字和为b[idx]
st[i]=true;
a[idx]=i;
if(dfs(idx+1))return true;
st[i]=false;
}
return false;
}
int main(){
cin>>n;
for (int i = 1; i <= n - 1; i ++ )scanf("%d",&b[i]);
for (int i = 1; i <= b[1]; i ++ ){
st[i]=true;
a[0] =i;
if(dfs(1)){
for (int j = 0; j < n; j ++ )
cout<<a[j]<<" ";
return 0;
}
st[i]=false;
}
}
给个赞和关注吧