Fork me on GitHub

2022/8/15 训练:搜索专栏(包含 Cleaning Robot,Bloxorz I,城市距离)

Cleaning Robot

 

  这道题可以先用bfs把任意两个脏点的最小距离算出来,然后利用TSP算出答案。

  TSP是什么?详见 百度百科 。

  至于这个TSP暴力怎么写,私以为very important。相当于全排列,似乎可以用next_permutation(),再求相邻两个点之间的mp[i-1][i]

 

模板
void dfs(int t,int sum,int dep) {  //当前编号, 当前最小次数 , 已经经过的编号数 
	if(sum>ans) return;
	if(dep==idx+1) {
		ans=min(ans,sum);
		return;
	}
	for(int i=1;i<idx;i++) {
		if(!f[i]) {
			f[i]=1;
			dfs(i,sum+mp[t][i],dep+1);//mp是从t到i的最短路径
			f[i]=0;
		}
	}
}

 

解题步骤:

  ①:将所有脏地板和起点(置为0号位)存入一个集合

  ②:跑bfs,计算出集合中两两的最小距离

  ③:暴力dfs枚举出这个图的所有路径,保存最小值并输出

 

Code
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
struct node{
    int x,y,l;
};
node u,v;
bool f[12];
node P[12];
queue<node> q;
char s[25][25];
int mp[12][12];
int r,c,pk,ans;
int dx[]={1,0,-1,0};
int dy[]={0,1,0,-1};
int fnd(int x,int y)
{
    for(int i=0;i<pk;i++)
        if(P[i].x==x&&P[i].y==y)
            return i;
}
void dfs(int t,int sum,int cur)//当前编号,当前最小次数,已经经过的编号数 
{
	if(sum>ans) return;
    if(cur==pk)
    {
        if(sum<ans) ans=sum;
            return;
    }
    for(int i=1;i<pk;i++)
        if(!f[i])
        {
            f[i]=1;
            dfs(i,sum+mp[t][i],cur+1);
            f[i]=0;
        }
}
int main()
{
    while(scanf("%d %d",&c,&r)&&c&&r)
    {
    	memset(mp,0x3f,sizeof(mp));
	    pk=1;
	    for(int i=0;i<r;i++)
	    {
			scanf("%s",s[i]);
	        for(int j=0;j<c;++j)//将脏地面与起点拉入集合 
	            if(s[i][j]=='o')
	                P[0].x=i,P[0].y=j,s[i][j]='*';//将起点置为0号位脏地板 
	                
	            else if(s[i][j]=='*')
	                P[pk].x=i,P[pk++].y=j; 
	    }
	    for(int i=0;i<pk;i++)//计算以每个脏地板两两之间的距离 
	    {
	        int f[25][25];
	        memset(f,0,sizeof(f));
	        u.x=P[i].x,u.y=P[i].y,u.l=0;
	        q.push(u);
	        f[u.x][u.y]=1;
	        int cnt=pk; 
	        while(!q.empty()&&cnt)
	        {
	            u=q.front();
	            q.pop();
	            for(int j=0;j<4&&cnt;++j)
	            {
	            	int xx,yy;
	                xx=u.x+dx[j],yy=u.y+dy[j];
	                if(xx<0||xx>=r||yy<0||yy>=c||s[xx][yy]=='x'||f[xx][yy])
	                    continue;
	                if(s[xx][yy]=='*')
	                {
	                    cnt--;
	                    mp[i][fnd(xx,yy)]=u.l+1;//xx,yy在几号位 
	                }
	                f[xx][yy]=1;
	                v.x=xx,v.y=yy,v.l=u.l+1;
	                q.push(v);
	            }
	        }
	        while(!q.empty())
	            q.pop();
	    }
        ans=0x3f3f3f3f;
        memset(f,0,sizeof(f));
        dfs(0,0,1);
        if(ans==0x3f3f3f3f||ans==0)
            ans=-1;
		printf("%d\n",ans);
    }
    return 0;
}

 

Bloxorz I

----------------------------------------------------------------------------------------------------------------------------------------

题目描述

  Bloxorz是一个风靡世界的小游戏。Bloxorz的地图是一个N行M列的矩阵,每个位置可能是硬地(用.表示)、易碎地面(用E表示)、禁地(用#表示)、起点(用X表示)或终点(用O表示)。

  你的任务是操作一个112的长方体。这个长方体在地面上有两种放置形式,“立”在地面上(11的面接触地面)或者“躺”在地面上(12的面接触地面)。在每一步操作中,可以按上下左右四个键之一。按下之后,长方体向对应的方向沿着棱滚动90度。任意时刻,长方体不能有任何部位接触禁地(否则就会掉下去),并且不能立在易碎地面上(否则会因为压强太大掉下去)。X标识长方体的起始位置,地图上可能有一个X或者两个相邻的X。地图上唯一的一个O标识目标位置。求把长方体移动到目标位置(即立在O上)所需要的最少步数。如果无解,输出Impossible。在移动过程中,X和O标识的位置都可以看作是硬地被利用,3<=N,M<=500。

这个盒子放在一个单元上

盒子水平放置在两个相邻的单元上

The box lies on two neighbouring cells, vertically

-------------------------------------------------------------------------------------------------------------------------------------------

图片来自:@

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
struct State
{
    int x,y,lie;
};
const int N = 510;
int n,m;
char g[N][N];
int dist[N][N][3];
bool check(int x,int y)
{
    if(x<0||x>=n||y<0||y>=m) return false;
    return g[x][y]!='#';
}
int bfs(State start,State end) 
{
	int d[3][4][3]={ //看着很唬人
        {{-2, 0, 2}, {0, 1, 1}, {1, 0, 2}, {0, -2, 1}},
        {{-1, 0, 1}, {0, 2, 0}, {1, 0, 1}, {0, -1, 0}},
        {{-1, 0, 0}, {0, 1, 2}, {2, 0, 0}, {0, -1, 2}}
    };
 
    queue<State> q;
	q.push(start);
    memset(dist,-1,sizeof dist);
	dist[start.x][start.y][start.lie]=0;
    
    while(q.size())
    {
        State t=q.front();
		q.pop();
        for(int i=0;i<4;i++)
        {
        	//t.lie为当前状态。如果t.lie==0,那么就枚举d数组的第一排 
            State next={t.x+d[t.lie][i][0],t.y+d[t.lie][i][1],d[t.lie][i][2]};//那一排,那一坨中的哪一个 

            int x=next.x, y=next.y;
            if(!check(x,y)) continue;
            if(next.lie==0 && g[x][y]=='E') continue;//立着不能立在易碎地面上
            if(next.lie==1 && !check(x,y+1)) continue;//横着的下一个是否满足
            if(next.lie==2 && !check(x+1,y)) continue;//竖着的下一个是否满足

            if(dist[next.x][next.y][next.lie]==-1)//相当于一个bool数组,看这个点是否搜过
            {
                dist[next.x][next.y][next.lie]=dist[t.x][t.y][t.lie]+1;
                q.push(next);
            }
        }
    }
    return dist[end.x][end.y][end.lie];
}
int main()
{
    scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++) scanf("%s",g[i]);
        State start={-1,0,0},end;
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
                if(g[i][j]=='X'&&start.x==-1)
                {
                    //初始的状态
                    if(g[i+1][j]=='X') start={i,j,2};
                    else if(g[i][j+1]=='X') start={i,j,1};
                    else start={i,j,0};
                }
                else if(g[i][j]=='O') end={i,j,0};

        int res=bfs(start,end);
        if(res==-1) puts("Impossible");
        else printf("%d\n",res);
    return 0;
}

 

城市距离

 

  我们可以把联通的一个城市看作同一个起点。整个过程相当于是确定起点,寻找终点的过程。

解题步骤:

①:遍历整个地图,用dfs找到一个连通块里的所有城市

②:当作起点压入队列,进行bfs,当第一次搜到'#',停止,比较答案

③:继续找下一个城市

 

Code
 #include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
const int Maxn = 5e2 + 5;
const int zx[4] = {-1, 0, 1, 0}, zy[4] = {0, 1, 0, -1};
int n, m, ans = 1e6;
char c[Maxn][Maxn];
bool vis[Maxn][Maxn];
struct node {
	int x, y, step;
}; 
queue<node> q;
void dfs(int x, int y) {
	c[x][y] = 'A';
	q.push((node){x, y, 0});
	for(int i = 0;i < 4; ++i) {
		int dx = x + zx[i], dy = y + zy[i];
		if(dx >= 1 and dy >= 1 and dx <= n and dy <= m and c[dx][dy] == '#') dfs(dx, dy);
	}
}
void bfs() {
	memset(vis, 0, sizeof(vis));
	while(!q.empty()) {
		node p = q.front();
		q.pop();
		if(c[p.x][p.y] == '#') {
			ans = min(ans, p.step);
			while(!q.empty()) q.pop(); 
			return ;
		}
		for(int i = 0;i < 4; ++i) {
			int dx = p.x + zx[i], dy = p.y + zy[i];
			if(dx >= 1 and dy >= 1 and dx <= n and dy <= m and !vis[dx][dy] and c[dx][dy] != 'A') {
				vis[dx][dy] = 1;
				q.push((node){dx, dy, p.step + 1});
			}
		}
	}
}
int main() {
    freopen("city.in","r",stdin);
    freopen("city.out","w",stdout);
	scanf("%d %d", &n, &m);
	for(int i = 1;i <= n; ++i) scanf("%s", c[i] + 1);
	for(int i = 1;i <= n; ++i)
		for(int j = 1;j <= m; ++j) {
			if(c[i][j] == '#') {
				dfs(i, j);
				bfs();
			} 
		}
	printf("%d", ans);
	return 0;
} 

 

 

 

posted @ 2022-08-18 08:51  Doria_tt  阅读(46)  评论(0)    收藏  举报