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

来源:互联网 发布:淘客网站源码建立 编辑:程序博客网 时间:2024/05/19 22:01
/*题意~:要你求能吃掉硬币的最多的个数,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 0
原创粉丝点击