#include <iostream>
#include <cmath>
#include <cstring>
using namespace std;
#define M 50
struct People
{
int pos;
bool lifted;//正在被举着
bool lifting;//正在举着别人
int lift;//举着的是谁
int maxmove;//最大移动距离
int maxthrow;//最大抛距离
bool hasmoved;//是否移动过
bool haslifted;//是否举过别人
//没有必要加上是否抛过别人的标记,因为只能举起别人一次
}p[3];
bool Pos[M];//数轴,作为标记是否某位置上有人
bool visit[10];//排序标记,有三个人且每个人有移动、举起、抛出三种状态,共有9种操作
int Max=0;//记录最大位置
void dfs(int k,int step)
{
int n = k / 3; //当前执行操作的人
int m = k % 3; //当前执行的动作
//move
if(m==0)
{
if(p[n].lifted || p[n].lifting || p[n].hasmoved) return;
int i=1;
if(step == 9) i=p[n].maxmove;//最后一步,则直接向前移动最大距离
/*如果不是最后一步,那么他也不必从他能移动的最靠后的距离开始搜索
他只需要从 他的位置之前的 有人的位置 的前一个位置 开始搜索即可
如果他后面没人,那么他走的距离只需要从1开始搜索,不需要往后走,只需要往前走*/
else
{
for(int j=1;j<p[n].pos;j++)
//从第一个位置到p[i]的当前位置遍历
{
if(Pos[j])//找p[i]前面有人的位置,以此来判断移动距离
{
int l = -(p[n].pos-j-1);//l为移动位置的 后一个位置
i= l<i?l:i;
}
}
i = i > -p[n].maxmove ? i : -p[n].maxmove;
//移动的距离不可以大于p[i]的最大移动距离
}//找出i---即最大移动多少步
for(;i <= p[n].maxmove; i++)
{
if(Pos[p[n].pos+i-1] || Pos[p[n].pos+i+1] || i==p[n].maxmove)
//移动到的位置 的 前后有人,才可以进行举起抛出,才有意义
{
if(p[n].pos+i >0 && !Pos[p[n].pos+i])
//不可以移动到数轴外,且移动的位置必须为空
{
if(!i) continue;//i=0,表示不移动,进入下一个for循环
Pos[p[n].pos]=false;//当前位置置零
p[n].pos += i;//move i步
Pos[p[n].pos]=true;//move后的位置 置为1
p[n].hasmoved=true;//标记
Max= p[n].pos>Max ? p[n].pos : Max;//记录最大位置
//向下一步 深搜
for(int j=0;j<9;j++)
{
if(!visit[j])
{
visit[j]=true;
dfs(j,step+1); //向下一步 深搜
visit[j]=false;//回溯
}
}
//回溯
Pos[p[n].pos]=false;
p[n].pos -= i;
Pos[p[n].pos]=true;
p[n].hasmoved=false;
}
}
}
}
//lift
else if(m==1)
{
if(p[n].lifted || p[n].lifting || p[n].haslifted) return;
for(int i=0;i<3;i++)
//找旁边的人,初始判断条件为两者距离为1
{
if(abs(p[i].pos-p[n].pos) == 1)
{
if(p[i].lifted) continue;//如果这个人正被举着,则不能重复举起
//否者,标记相关信息
p[n].haslifted=true;
p[n].lifting=true;
p[n].lift=i;
p[i].lifted=true;
int temp=p[i].pos; //临时中间变量,以便回溯
Pos[p[i].pos]=false;//i被举起,则位置p[i].pos为空
p[i].pos=p[n].pos;//p[i]的位置即为p[n]的位置
//如果被举起的人i正在举着别人,则i举着的那个人的位置也要改变
if(p[i].lifting)
{
int j=p[i].lift;// j就是被i举着的人
p[j].pos=p[i].pos;
}
//继续搜索
for(int j=0;j<9;j++)
{
if(!visit[j])
{
visit[j]=true;
dfs(j,step+1);//向下一步深搜
visit[j]=false;
}
}
//回溯(将一切标记过的或者改动过的还原)
p[n].haslifted=false;
p[n].lifting=false;
p[n].lift= -1;
p[i].lifted=false;
p[i].pos=temp;//临时变量的作用即为 记下p[i]的原始位置,便于i还原
Pos[p[i].pos]=true;
//p[i]举着的人j也要记得还原为 :p[j]所被p[i]举着的位置
if(p[i].lifting)
{
int j=p[i].lift;// j就是被i举着的人
p[j].pos=p[i].pos;
}
}
}
}
//throw
else
{
if(!p[n].lifting || p[n].lifted) return;
//如果这个人并没有举着别人,这或个人正被举着,则退出
int i=1;
if(step == 9) i=p[n].maxthrow;//最后一步,直接向前抛出最大距离
else
{
for(int j=1;j<p[n].pos;j++)
//从第一个位置到p[i]的当前位置遍历
{
if(Pos[j])//找p[i]前面有人的位置,以此来判断抛出距离
{
int l=-(p[n].pos-j-1);//l为抛出位置的 后一个位置
i=l<i?l:i;
}
}
i= i> -p[n].maxthrow? i : -p[n].maxthrow;
//抛出的距离不可以大于p[i]的最大抛出距离
}//找出i---即最大抛出多少步
for( ;i <= p[n].maxthrow; i++)
{
if(Pos[p[n].pos+i-1] || Pos[p[n].pos+i+1] || i == p[n].maxthrow)
//抛出到的位置 的 前后为空,才有意义
{
if(p[n].pos+i>0 && !Pos[p[n].pos+i])
//不可以抛出到数轴外,且抛出所到的位置必须为空
{
int j=p[n].lift;//j为要被抛出的(即n举着的)人
p[j].pos += i;//j 被throw i步
Pos[p[j].pos]=true;//throw后的位置 置为1
p[n].lifting=false;//标记
p[n].lift = -1;
p[j].lifted=false;//抛出后即为不再是被举起状态
Max= p[j].pos>Max ? p[j].pos : Max;//记录最大位置
//若被抛出的j的头顶上还举着人
if(p[j].lifting)
{
int k=p[j].lift;//k为被j举着的人
p[k].pos=p[j].pos;//k的位置与j位置同步
}
//向下一步 深搜
for(int q=0;q<9;q++)
{
if(q == k) continue;//
if(!visit[q])
{
visit[q]=true;
dfs(q,step+1); //向下一步 深搜
visit[q]=false;//回溯
}
}
//回溯
Pos[p[j].pos]=false;
p[j].pos -= i;
p[j].lifted=true;
p[n].lift=j;
p[n].lifting=true;
if(p[j].lifting)
{
int k=p[j].lift;
p[k].pos=p[j].pos;
}
}
}
}
}
}
int main()
{
memset(Pos, false, sizeof(Pos));
memset(visit, false, sizeof(visit));
//输入
for(int i = 0; i < 3; i++)
{
cin >> p[i].pos >> p[i].maxmove >> p[i].maxthrow;
p[i].lifted = p[i].lifting = p[i].hasmoved = p[i].haslifted = false;
p[i].lift = -1;
Pos[p[i].pos] = true;
}
//深搜
for(int i = 0; i < 9; i++)
{
//一个合法的第一步,不可能是抛。必须先移动或者举起别人
if((i % 3) != 2)
{
visit[i] = true;
dfs(i, 1);
visit[i] = false;//回溯
}
}
//结果
cout << Max << endl;
return 0;
}
蓝桥杯算法训练——lift and throw
最新推荐文章于 2020-04-14 12:02:10 发布