/*
题意~:要你求能吃掉硬币的最多的个数,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);
}
}
湖南省第八届省赛题!!csu1119 Collecting Coins
最新推荐文章于 2022-09-28 23:27:30 发布