51nod - 1560 扔人游戏 - dfs(全排列思维)

力推这篇博客!非常感谢,写的很详细 https://blog.csdn.net/yoer77/article/details/53707149


附上代码:

#include<bits/stdc++.h>
using namespace std;

#define runfile freopen("E:/Code/CB/Root/data.txt", "r", stdin)
#define stopfile fclose(stdin)

struct People
{
    int pos;
    bool lifted;//正在被举着
    bool lifting;//正在举着别人
    int lift;//举着的是谁
    int maxMove;//最大的可移动的距离
    int maxThrow;//最大的可扔出的距离
    bool hasMoved;//是否移动过
    bool haslifted;//是否举过别人

}p[3];

bool vis[10],pos[50];
//3个人每人3个动作,一共9个操作。全排列这9个操作,标记重复
//标记数轴的每个位置是否有人
int ans = 0;

void dfs(int k, int step)
{
    int n = k/3;//当前执行的人
    int m = k%3;//当前执行的动作
    //move
    if(!m)
    {
        //如果他正在举着别人、正在被举着、已经移动过,那么他都不能移动
        if(p[n].lifting || p[n].lifted || 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++)
            {
                if(pos[j])
                {
                    int l = -(p[n].pos - j - 1);
                    i = min(l, i);
                }
            }
            i = max(-p[n].maxMove, i);//走的距离不能超过maxMove
        }
        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;

                    pos[p[n].pos] = false;//当前位置设置为false
                    p[n].pos += i;//向前走
                    pos[p[n].pos] = true;//走到的新位置置为true
                    p[n].hasMoved = true;//标记为已经移动过
                    ans = max(p[n].pos, ans);

                    //继续搜索
                    for(int j = 0; j < 9; j++)
                    {
                        if(!vis[j])
                        {
                            vis[j] = true;
                            dfs(j, step+1);
                            vis[j] = false;//回溯
                        }
                    }
                    //回溯
                    p[n].hasMoved = false;
                    pos[p[n].pos] = false;
                    p[n].pos -= i;
                    pos[p[n].pos] = true;
                }
            }
        }
    }
    //lift
    else if(m == 1)
    {
        //如果当前这个人正在被举着或者真在举着别人,或者已经举起过别人了,那么他不能再将别人举起
        if(p[n].lifted || p[n].lifting || p[n].haslifted)   return;
        for(int i = 0; i < 3; i++)
        {
            //如果旁边有人
            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;
                p[i].pos = p[n].pos;
                //如果当前举起的人正在举着其他人,那么这两个人的位置必须同步修改
                if(p[i].lifting)
                {
                    int j = p[i].lift;
                    p[j].pos = p[i].pos;
                }

                //继续搜索
                for(int j = 0; j < 9; j++)
                {
                    if(!vis[j])
                    {
                        vis[j] = true;
                        dfs(j, step+1);
                        vis[j] = false;
                    }
                }
                //回溯
                p[n].haslifted = false;
                p[n].lifting = false;
                p[n].lift = -1;
                p[i].lifted = false;
                p[i].pos = temp;
                pos[p[i].pos] = true;
                if(p[i].lifting)
                {
                    int j = p[i].lift;
                    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++)
            {
                if(pos[j])
                {
                    int l = -(p[n].pos - j - 1);
                    i = min(l, i);
                }
            }
            i = max(i, -p[n].maxThrow);
        }

        for(; i <= p[n].maxThrow; i++)
        {
            if(p[n].pos + i > 0 && !pos[p[n].pos+i])
            {
                if(pos[p[n].pos+i-1] || pos[p[n].pos+i+1] || i == p[n].maxThrow)
                {
                    int j = p[n].lift;
                    p[j].pos += i;
                    p[n].lifting = false;
                    p[n].lift = -1;
                    p[j].lifted = false;
                    pos[p[j].pos] = true;
                    ans = max(p[j].pos, ans);
                    if(p[j].lifting)
                    {
                        int k = p[j].lift;
                        p[k].pos = p[j].pos;
                    }
                    for(int q  = 0; q < 9; q++)
                    {
                        if(q == k)  continue;
                        if(!vis[q])
                        {
                            vis[q] = true;
                            dfs(q, step + 1);
                            vis[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()
{
//    runfile;
    ios::sync_with_stdio(false);
    memset(vis, 0, sizeof(vis));
    memset(pos, 0, sizeof(pos));
    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)
        {
            vis[i] = true;
            dfs(i, 1);
            vis[i] = false;
        }
    }
    cout<<ans<<endl;

//    stopfile;
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值