湖南省第八届省赛题!!csu1119 Collecting Coins

/*
题意~:要你求能吃掉硬币的最多的个数,O代表石头,X代表障碍物 .代表路 C代表硬币。石头只能推一次
推完就滚到在你正对着石头的后面一个位置就变成障碍,石头只能在后面为“·”的时候推,其余时候不能推。
思路: 刚开始用dfs爆搜~~结果想错了,那样肯定超时,以吃硬币判重,然后那里一共有最多
10枚硬币,那就是vis【10】【10】【10】了,一百个格子,每个格子最多可以跑10个,也就是
dfs有100^10次方个节点。直接爆搜果断超。
后来看了下网上的思路:然后代码是自己写的,先用dfs或bfs把不推石头就能吃掉的硬币吃掉,然后枚举石头每个石头全排列推
就是5!石头的全排列,因为有可能先退这个石头比先退那个石头吃的多些,然后每个石头有四个方向可以推。
也就是没个石头有四种状态。中然后最多有100个格子,也就是最多 5!*4*100个节点。这样比之前还是少了很多
很多了。  然后推一次石头跑一次dfs,求硬币最多者+上之前没推石头的就是答案了~~
*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct node{
   int x,y,flag;
};
node st[6];
node ccc[11];
int n,m;
int vis[30][30];
char map[30][30];
int zx,zy;
int cnt;
int res,ans,ans1;
int c,co;
int dir[4][2]={1,0,-1,0,0,1,0,-1};
int jude(int x,int y)
{
    if(x<1||x>n||y<1||y>m) return 0;
    return 1;
}
void dfs(int x,int y)
{
    if(map[x][y]=='C') res++,map[x][y]='.';
    vis[x][y]=1;
    for(int i=0;i<4;i++)
    {   int xx=x+dir[i][0];
        int yy=y+dir[i][1];
        if(!jude(xx,yy)||vis[xx][yy]||map[xx][yy]=='O'||map[xx][yy]=='X') continue;
        dfs(xx,yy);
    }
}
void dfs4(int x,int y,node *df,int &co)//推完一个石头能吃到的金币个数
{
    if(map[x][y]=='C') res++,map[x][y]='.',df[co].x=x,df[co++].y=y;//记录金币的位置,后面回溯。
    vis[x][y]=1;
    for(int i=0;i<4;i++)
    {   int xx=x+dir[i][0];
        int yy=y+dir[i][1];
        if(!jude(xx,yy)||vis[xx][yy]||map[xx][yy]=='O'||map[xx][yy]=='X') continue;
        dfs4(xx,yy,df,co);

    }
}
int dfs1(int x,int y,int zx,int zy)//判断是否能到达推石头的那个点。
{
    vis[x][y]=1;
    if(x==zx&&y==zy) return 1;
    for(int i=0;i<4;i++)
    {   int xx=x+dir[i][0];
        int yy=y+dir[i][1];
        if(!jude(xx,yy)||vis[xx][yy]||map[xx][yy]=='X'||map[xx][yy]=='O') continue;
        if(dfs1(xx,yy,zx,zy)) return 1;
    }
    return 0;
}
void solove(int num,int sum)//第几个石头,金币和
{
    if(num==cnt-1)//最后一个石头推完
        {
            if(ans1<sum) ans1=sum;
            return ;
        }
    if(ans+ans1==c) return ;
    for(int i=1;i<cnt&&ans+ans1<c;i++)//暴力枚举石头
    {
        if(!st[i].flag) continue ;
        st[i].flag=0;
        for(int j=0;j<4;j++)//枚举方向
        {
            int xx=st[i].x+dir[j][0];//根据你的位置得到的石头的前后位置。
            int yy=st[i].y+dir[j][1];
            int x2=st[i].x-dir[j][0];
            int y2=st[i].y-dir[j][1];
            if(!jude(xx,yy)||map[xx][yy]=='C'||map[xx][yy]=='O'||map[xx][yy]=='X') continue;//当石头后面不为空或者出界
            if(!jude(x2,y2)||map[x2][y2]=='O'||map[x2][y2]=='X') continue;//当人站的那个位置还有石头或者为障碍
            memset(vis,0,sizeof(vis));
            if(!dfs1(zx,zy,x2,y2)) continue;//当人不能到达推石头的那个位置
            map[st[i].x][st[i].y]='.';//能推就把石头那个位置变成路
            map[xx][yy]='X';//石头后面的位置变成障碍
            memset(vis,0,sizeof(vis));
            int co=0;
            node *df=(node*)malloc(sizeof(node)*10);//最多是个金币,用来保存这一轮完石头所吃的金币位置用于后面的回溯
             res=0;
            dfs4(zx,zy,df,co);//推完这次石头然后去吃硬币
            solove(num+1,sum+res);//继续往下面枚举石头
             for(int k=0;k<co;k++)//回溯地图上的金币
            {
               map[df[k].x][df[k].y]='C';
            }
            map[st[i].x][st[i].y]='O';//回溯石头的位置
            map[xx][yy]='.';

        }
        st[i].flag=1;
        if(ans1<sum) ans1=sum;//取最大
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d",&n,&m);
        cnt=1;
        c=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%s",map[i]+1);
            for(int j=1;j<=m;j++)
            {
                if(map[i][j]=='S')
                {
                    zx=i;
                    zy=j;
                    map[i][j]='.';

                }
                if (map[i][j] == 'C') c++;
                if(map[i][j]=='O')
                {
                    st[cnt].x=i,st[cnt].y=j;
                    st[cnt++].flag=1;
                }
            }
        }
        res=0;
        memset(vis,0,sizeof(vis));
        dfs(zx,zy);//不推石头直接能吃的金币个数
        ans=res;
        ans1=0;
        solove(0,0);
        printf("%d\n",ans+ans1);
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: CSU飞跃手册2019是一个以服务学生发展为宗旨的学生服务项目,帮助学生实现个人成长和职业发展目标。飞跃手册提供了诸如成功学、职业规划、就业技巧以及个人发展等方面的指导,帮助学生掌握自我认知、提升职场竞争力并构建良好的人脉关系。 飞跃手册2019包括三个模块。第一个模块着重讲解如何探索自我,明确职业目标和规划职业道路。这些关键的步骤帮助学生发现自己的职业特长和兴趣爱好,从而为个人职业发展做出决策和规划。 第二个模块提供了职业发展过程中的必备技能,如招聘面试技巧、简历写作、职场沟通、决策和问解决能力,以及管理和领导力等。这些技能帮助学生在职场中不断学习和成长,并展示自己的优势。 第三个模块则介绍如何利用社会资源和人脉关系来推动个人职业发展。它包括了网络管理、人脉建立、社交礼仪和社会责任等方面的指导。 总之,CSU飞跃手册2019是一份应对职场挑战和工作生涯的指南, 帮助学生建立自己的职业目标并实现自我发展。它讲解了个人成长、职场技能、人脉力量和社会责任等方面的内容,为学生的成功创造了一个强有力的支撑体系。 ### 回答2: CSU飞跃手册2019是一本由中国海洋大学控制科学与工程学院发行的指导学生爆炸性训练和实习的手册。该手册将学生分为不同职业兴趣组,并提供了具体的介绍、岗位培训以及实习就业方案。 该手册还包括了部分参考书目、学术论文和个人成长方向的建议,在实习期间指导学生更好地发展个人能力和提高自己的竞争力。除此之外,该手册还有一些校内外的实践活动介绍和经验分享。这些活动涵盖了多个不同领域,包括科技、创业、环保和社会公益等。 该手册还提供了一些面试技巧和求职指南,帮助学生更好地应对就业市场的挑战。此外,该手册还鼓励学生通过网络平台和社会实践等多种途径积累人脉资源,增强自己的社交和交际技巧。 总的来说,CSU飞跃手册2019为学生提供了一个全面的指导工具,帮助他们更好地理解职业规划,提高个人素质,扩展职业视野并实现自我价值。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值