DEF题解

D . Knight Moves

题目大意:在一个棋盘上给出起点和终点,棋子以走‘日’的方式以最短的路径前往终点。

题目分析:用广度优先搜索,将输入的字符串转化为坐标,然后按照象棋中马的走法前往终点。

#include<bits/stdc++.h> 
using namespace std;
typedef long long ll;
ll mp[26][26],vis[26][26];
ll ty[8] = {-1, 1, -2, 2, -2, 2, -1, 1};
ll tx[8] = {-2, -2, -1, -1, 1, 1, 2, 2};
char a[3],b[3];
ll sx,sy,ex,ey,n,m,flag,minstep;
struct node
{
 ll x,y,step;
};
void bfs()
{
 queue<node> que;
 node q,p;
 q.x=sx,q.y=sy,q.step=0;
 que.push(q);
 while(!que.empty())
 {
  q=que.front();
  if(q.x==ex&&q.y==ey)
   {
    printf("To get from %s to %s takes %d knight moves.\n",a,b,q.step);
    return ;
   }
  que.pop();
  for(int i=0;i<8;i++)
    {
      p=q;
      p.x+=tx[i];p.y+=ty[i];
     if(p.x>=1&&p.x<=8&&p.y>=1&&p.y<=8)
        if(!vis[p.x][p.y])
        {
           p.step=p.step+1;
           vis[p.x][p.y]=1;
           que.push(p);
        }
    }
 }
}
int main()
{
    while(scanf("%s%s",&a,&b)!=EOF)
    {
     memset(vis,0,sizeof(vis));
     minstep=1000000;
     sx=a[0]-'a'+1;sy=a[1]-'0';
     ex=b[0]-'a'+1;ey=b[1]-'0';
     vis[sx][sy]=1;
     bfs();
    }
    return 0;
}

E.Patrol Robot

题目大意:一个机器人在m*n的范围内移动,且每一步只能移动一格,移动方向只能有上下左右四个方向,其中会有单元格有障碍物,不能连续穿过超过k个障碍物,求起点到终点的最短路径。

题目分析:一般想到使用bfs,但是多出了障碍物,需要判断穿过或是绕弯,其中遇到四周都为障碍物和穿过次数超过k时无解,输出-1.仅使用bfs无法解决障碍物的问题。队列中存放的结构体中有当前位置的坐标,x,y,还有已经走过的步数member,以及连续走过的障碍方格的个数count. 对于下标不满足条件以及vis标记走过的方格,和连续走过方格的个数超过k的位置,都不放入队列,反之放入队列,继续bfs,直至第一次到达右下角为止。因为每一个从平行的bfs状态下走到同一障碍方格时,可能之前连续走过的障碍方格的个数不同。
所以,在同一位置,会有0~k不同的方格个数的选择,选用二维vis标记数组标记,情况考虑不全的同时还会超时,使用三维vis 标记数组标记,多出的一维用来记录该方格之前连续走过的障碍方格的个数。

#include<bits/stdc++.h>
typedef long long ll; 
using namespace std;
struct pc{
    int x,y,member,countt;
};
ll ter[4][2]={1,0,0,1,-1,0,0,-1};
ll maze[110][110],vis[110][110][25];
ll n,m,k;
ll bfs()
{
    ll i,xx,yy;
    queue<pc> q;
 
    memset(vis,0,sizeof(vis));
    pc now,no;
    now.x=0; now.y=0;
    now.member=1; now.countt=0;
    q.push(now);
    vis[0][0][0]=1;
    while(!q.empty()){
        no=q.front();
        q.pop();
        if(no.x==n-1&&no.y==m-1)
            return no.member-1;
        for(i=0;i<4;i++){
            now.x=no.x+ter[i][0];
            now.y=no.y+ter[i][1];
            if(now.x>=0 && now.x<n &&now.y>=0 &&now.y<m){
                if(maze[now.x][now.y]==1)
                    now.countt=no.countt+1;
                else
                    now.countt=0;
                if(now.countt<=k&&vis[now.x][now.y][now.countt]==0)
                {   now.member=no.member+1;
                    q.push(now);
                }
                vis[now.x][now.y][now.countt]=1;
            }
        }
    }
    return -1;
}
int main()
{   
    ll f,i,j;
    cin>>f;
    while(f--){
        cin>>n>>m>>k;
        for(i=0;i<n;i++){
            for(j=0;j<m;j++){
                cin>>maze[i][j];
            }
        }
        cout<<bfs()<<endl;
    }
    return 0;
}

F.Equilibrium Mobile

题目大意:输入字符串,为天平上磅秤的位置和重量,可以任意修改磅秤的重量,要使天平平衡最少需要修改几个磅秤

题目分析:天平结构为二叉树,在知道磅秤的重量w和深度下可以求出这个数的总重量=w*pow(2,depth),因为在某个深度下的完全二叉树节点个数=pow(2,edpth)。因为要使天平平衡那么这层深度的节点的重量全部等于w,再乘上个数就是这棵树的总重量。然后用位运算表示就是:总重量=w<<depth。然后求出每个节点平衡的总重量,那么必然会有一些相等的情况,我们把这写总重量相同的数量计数,也就是说可以得到某个总重量,不需要改变值的数量是w[i],这里用map记录 map[n][w]:表示总重量为w不需要改变n个数,然后我们找到最大多需要改变的数量,用总节点数-最多不需要改变的数量=最少需要改变的数量。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mm=1e6+5;
ll sum=0;
char str[mm];
map<ll,ll>mp;
void dfs(int s,ll t,ll dep){
	if(str[s]=='['){
		int p=0;
		for(ll i=s+1;i<=t;i++){
			if(str[i]=='[')p++;
			if(str[i]==']')p--;
			if(p==0&&str[i]==','){
				dfs(s+1,i-1,dep+1);
				dfs(i+1,t-1,dep+1);
			} 
		}
	}
	else{
		ll w=0;
		for(ll i=s;i<=t;i++){
			w=w*10+(str[i]-48);
		}
		++mp[w<<dep];++sum;
	}
}
int main(){
	ll t;
	cin>>t;
	while(t--){
		mp.clear();
		cin>>str;
		sum=0;
		dfs(0,strlen(str)-1,0);
		ll maxn=0;
		for(map<ll,ll>::iterator it=mp.begin();it!=mp.end();it++){
			maxn=max(maxn,it->second);
		}
		cout<<sum-maxn<<endl;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值