算法训练 数字游戏
题目
资源限制
时间限制:1.0s
内存限制:256.0MB
问题描述
给定一个1~N的排列a[i],每次将相邻两个数相加,得到新序列,再对新序列重复这样的操作,显然每次得到的序列都比上一次的序列长度少1,最终只剩一个数字。
例如:
3 1 2 4
4 3 6
7 9
16
现在如果知道N和最后得到的数字sum,请求出最初序列a[i],为1~N的一个排列。若有多种答案,则输出字典序最小的那一个。数据保证有解。
输入格式
第1行为两个正整数n,sum
输出格式
一个1~N的一个排列
样例输入
4 16
样例输出
3 1 2 4
数据规模和约定
0<n<=10
分析
-
输出样例 3 1 2 4 为 1-4 的数
-
全排列求和比较是否等于sum
-
由于满足要求的结果可能有多个,还需比较字典序,选择小的
-
比较字典序:假设下列三个结果都满足结果
3 1 2 4
3 2 1 4
4 3 2 1
每得出一个结果就与上一次的结果相比较,如果字典序小,就将上一次存储的结果替换。否则,继续搜索下一次结果。
DFS排序树模板
排序树
int x[n];
void backtrack (int t)
{ if (t>n) output(x);
else
for (int i=t;i<=n;i++) {
swap(x[t], x[i]);
if (constraint(i) && bound(i))
backtrack(t+1);
swap(x[t], x[i]);
}
}
代码
#include<iostream>
using namespace std;
int a[1000],b[1000],x[1000];
int n,m;
//检查是否满足sum
bool check()
{
for(int i=0;i<n;i++)
b[i]=a[i];
for(int i=n;i>1;i--)
{
for(int j=0;j<i-1;j++)
{
b[j]=b[j]+b[j+1];
}
}
// cout << "fasdfsd"<<b[0]<<endl;
if(b[0]==m)
{
return true;
}
return false;
}
//比较字典序
bool zipmin()
{
for(int i=0;i<n;i++)
{
if(a[i]==x[i])
continue;
else if(a[i]<x[i])
{
return true;
}
else
return false;
}
// return false;
}
//全排列
void dfs(int i)
{
if(i>=n)
{
// if(check())
// cout<<"yes";
if(check()&&zipmin())
{
for(int k=0;k<n;k++)
{
// cout << a[k]<<" ";
x[k]=a[k];
}
}
// cout <<endl;
}
else{
for(int j=i;j<n;j++)
{
swap(a[i],a[j]);
dfs(i+1);
swap(a[i],a[j]);
}
}
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)
{
a[i]=i+1;
x[i]=n;
}
dfs(0);
for(int k=0;k<n;k++)
{
cout << x[k]<<" ";
// x[k]=a[k];
}
return 0;
}
//得分 90
算法训练 无聊的逗
题目
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
逗志芃在干了很多事情后终于闲下来了,然后就陷入了深深的无聊中。不过他想到了一个游戏来使他更无聊。他拿出n个木棍,然后选出其中一些粘成一根长的,然后再选一些粘成另一个长的,他想知道在两根一样长的情况下长度最长是多少。
输入格式
第一行一个数n,表示n个棍子。第二行n个数,每个数表示一根棍子的长度。
输出格式
一个数,最大的长度。
样例输入
4
1 2 3 1
样例输出
3
数据规模和约定
n<=15
分析
通过题目可知是从已有的木棍中选择一组n根木棍与选择一组m根木棍,比较n根木棍长度和
等于m根木棍长度和
且长度最大。
1 2 3 1 编码 (1 1 1 1)表示都取,(0 0 0 0)表示都不取,2^n个组合。
DFS 子集树 将木棍分成三种情况(选 不选 放弃)
如果需要记录选择的木棍 定义x[ ] (1 0 -1)来表示木棍的状态
DFS子集树模板
子集树
int x[n];
void backtrack(int i)
{ if(i>n) output(x) ;
else
{ for (j=0;j<=1;j++)
{ x[i]=j;
if (constraint(i) && bound(i))
backtrack(i+1);
}
}
代码
#include<iostream>
#include<algorithm>
using namespace std;
int n,a[20];//长度 数组
int maxsum=0;
//将木棍分成三种情况(选 不选 放弃)
// 深搜 下标 左堆 右堆
void dfs(int i,int l,int r)
{
if (l==r && maxsum < l)
{
maxsum = l;
}
else
{
//dfs剪枝(左堆小于右堆) 或 下标越界
if(l > r && i < n){
dfs(i+1,l,r);//不选
dfs(i+1,l-a[i],r+a[i]);//选
dfs(i+1,l-a[i],r);//放弃
}
}
}
int main()
{
cin >> n;
int sum=0;
for(int i=0;i<n;i++)
{
cin >> a[i];
sum=sum+a[i];
}
sort(a,a+n);
dfs(0,sum,0);
cout<<maxsum;
return 0;
}