算法题小总结(3)

目录

1.未来之迷

思路

代码展示

2.不要分心

思路

代码展示

3.过河卒

思路

代码展示

4.地毯

思路

代码展示

5.最小新整数

思路

代码展示

6.宇航员

思路

代码展示


1.未来之迷

/**在2022年,Mike发现了两个长度为n的二进制整数a和b(它们都只由数字0和1表示),前导可以有0。为了不忘记它们,他想用以下方式构造整数d:
他创建了一个整数c作为a和b的位和的结果,没有转移进位,所以c可能有一个或多个2。例如,0110与1101的按位求和的结果是1211,或者011000与011000的和是022000;
Mike将c中相等的连续数字替换为1位,得到d。在上述情况下,进行此操作后,1211变成了121,022000变成了020(所以d没有相等的连续数字)。
不幸的是,迈克在自己计算d之前就失去了整数a。现在,为了让他高兴起来,你要找到任何长度为n的二进制整数a使d作为整数的最大值。
最大可能的整数表示102>21,012<101,021=21,以此类推。
输入
第一行包含单个整数t(1≤t≤1000)-测试用例的数量。
每个测试用例的第一行包含整数n(1≤n≤10^5) a和b的长度。
每个测试用例的第二行包含长度为n的二进制整数b。整数b仅由数字0和1组成。
它保证了n对所有t个测试用例的总和不超过10^5。
输出
对于每个测试用例输出一个长度为n的二进制整数a。注意,a或b可以有前导0,但必须有相同的长度n。
请注意
在第一个测试用例中,b=0,选择a=1,结果是d=1。
在第二个测试用例中,b=011所以:
如果a=000, c = 011,那么d=01;
如果a=111, c = 122,那么d=12;
如果选a=010,得到d=021。
如果你选择a=110,你会得到d=121。
我们可以证明答案a=110是最优的,而d=121是最大可能的。
在第三个测试案例中,b=110。如果选a=100,就得到d=210,这是d的最大值。
在第四个测试用例中,b=111000。如果你选择a=101101,你会得到d=212101,这是最大可能的d。
在第五个测试用例中,b=001011。如果你选择a=101110,你会得到d=102121,这是最大可能的d。*/

思路

注意组合出来的数字,若相邻两个数字相同,则会合并,而A的每一位数字均由0或1组成,要使得C最大,则第一位取1,后面的数字尽量往大了取,并且保证与上一位不重复。

代码展示

#include<stdio.h>

int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n;
		scanf("%d",&n);
		getchar();
		int i,b=0,a[100005]={0};
		while((a[b]=getchar())!='\n')
			b+=1;
		printf("1");
		a[0]++;
		for(i=1;i<b;i++)
		{
			if(a[i-1]=='2')
			{
				if(a[i]=='1')
					printf("0");
				else{
					printf("1");
					a[i]++;
				}
					
			}
			else if(a[i-1]=='1')
			{
				if(a[i]=='1')
				{
					a[i]++;
					printf("1");
				}
				else
					printf("0");
			}	
			else
			{
				printf("1");
				a[i]++;
			}
		}printf("\n");
	}
	return 0;
}

2.不要分心

/*Polycarp has 26 tasks. Each task is designated by a capital letter of the Latin alphabet.

The teacher asked Polycarp to solve tasks in the following way: if Polycarp began to solve some task, then he must solve it to the end, without being distracted by another task. After switching to another task, Polycarp cannot return to the previous task.

Polycarp can only solve one task during the day. Every day he wrote down what task he solved. Now the teacher wants to know if Polycarp followed his advice.

For example, if Polycarp solved tasks in the following order: “DDBBCCCBBEZ”, then the teacher will see that on the third day Polycarp began to solve the task ‘B’, then on the fifth day he got distracted and began to solve the task ‘C’, on the eighth day Polycarp returned to the task ‘B’. Other examples of when the teacher is suspicious: “BAB”, “AABBCCDDEEBZZ” and “AAAAZAAAAA”.

If Polycarp solved the tasks as follows: “FFGZZZY”, then the teacher cannot have any suspicions. Please note that Polycarp is not obligated to solve all tasks. Other examples of when the teacher doesn’t have any suspicious: “BA”, “AFFFCC” and “YYYYY”.

Help Polycarp find out if his teacher might be suspicious.

Input
The first line contains an integer t (1≤t≤1000). Then t test cases follow.

The first line of each test case contains one integer n (1≤n≤50) — the number of days during which Polycarp solved tasks.

The second line contains a string of length n, consisting of uppercase Latin letters, which is the order in which Polycarp solved the tasks.

Output
For each test case output:

“YES”, if the teacher cannot be suspicious;
“NO”, otherwise.
You may print every letter in any case you want (so, for example, the strings yEs, yes, Yes and YES are all recognized as positive answer).

Example
input
5
3
ABA
11
DDBBCCCBBEZ
7
FFGZZZY
1
Z
2
AB
output
NO
NO
YES
YES
YES*/

思路

判断字符串是否重复出现,不必多说

代码展示

#include <stdio.h>
#include <string.h>

int main()
{
	char a[1001];
	int b[1001] = {0};
	int n, i, j, k, len;
	scanf("%d", &n);
	for (i = 0; i < n; i++) {
		scanf("%d", &len);
		scanf("%s", a);
		for (j = 0; j < len; j++) {
			if (a[j] != a[j - 1]) {
				for (k = 0; k < j; k++) {
					if (a[k] == a[j]) {
						b[i] = 1;
						break;
					}
				}
			}
			if (b[i] == 1)
				break;
		}
	}
	for (i = 0; i < n; i++) {
		if (b[i] == 0)
			printf("YES\n");
		else
			printf("NO\n");
	}
    return 0;
}

3.过河卒

思路

把马和马能到的地方标记,然后按顺序对坐标进行更新,a[x,y]=a[x-1,y]+a[x,y-1],最后输出a[x,y]的值。

代码展示

#include<stdio.h>

int main()
{
	int x1,x2,y1,y2;
	long long int a[30][30];
	scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
	//所有不能通过的位置 
    a[x2][y2]=-1;
	if(y2-2>=0 && x2+1<=x1)
		a[x2+1][y2-2]=-1;
	if(y2-2>=0 && x2-1>=0)
		a[x2-1][y2-2]=-1;
	if(y2-1>=0 && x2+2<=x1)
		a[x2+2][y2-1]=-1;
	if(y2-1>=0 && x2-2>=0)
		a[x2-2][y2-1]=-1;
	if(y2+1<=y1 && x2+2<=x1)
		a[x2+2][y2+1]=-1;
	if(y2+1<=y1 && x2-2>=0)
		a[x2-2][y2+1]=-1;
	if(y2+2<=y1 && x2+1<=x1)
		a[x2+1][y2+2]=-1;
	if(y2+2<=y1 && x2-1>=0)
		a[x2-1][y2+2]=-1;
	for(int i=1;i<=x1;i++)
	{
		if(a[0][i]==-1)
		{
			for(int j=i+1;j<=y1;j++)
			{
				if(a[0][j]!=-1)
				a[0][j]=0;
			}
			break;
		}else{
			a[0][i]=1;
		}
	}
	for(int i=1;i<=y1;i++)
	{
		if(a[i][0]==-1)
		{
			for(int j=i+1;j<=x1;j++)
			{
				if(a[j][0]!=-1)
				a[j][0]=0;
			}
			break;
		}else{
			a[i][0]=1;
		}
	}
	for(int i=1;i<=x1;i++)
	    for(int j=1;j<=y1;j++)
	    {
	    	if(a[i][j]!=-1)
	    	{
	    		if(a[i-1][j]==-1&&a[i][j-1]==-1){
	    			a[i][j]=0;
				}else if(a[i-1][j]==-1&&a[i][j-1]!=-1){
					a[i][j]=a[i][j-1];
				}else if(a[i-1][j]!=-1&&a[i][j-1]==-1){
					a[i][j]=a[i-1][j];
				}else if(a[i-1][j]!=-1&&a[i][j-1]!=-1){
					a[i][j]=a[i][j-1]+a[i-1][j];
				}
			}
		}
	printf("%lld\n",a[x1][y1]);
	return 0;
}

#include<stdio.h>

long long dp[30][30];
int main()
{
    int n,m,a,b,i,j;
    scanf("%d%d%d%d",&a,&b,&n,&m);
    m++;n++;a++;b++;
    for(i=1;i<=a;i++)
        for(j=1;j<=b;j++)
        {
            if(i==1 && j==1)
                dp[i][j] = 1;
            else if((i==n&&j==m) || (i==n-1&&j==m-2) || (i==n-2&&j==m-1) || (i==n-2&&j==m+1) || (i==n-1&&j==m+2) || (i==n+1&&j==m+2) 	|| (i==n+2&&j==m+1) || (i==n+2&&j==m-1) || (i==n+1&&j==m-2))
                dp[i][j]=0;		
            else if(i!=1 || j!=1) 	
                dp[i][j] = dp[i-1][j]+dp[i][j-1];
        }
    printf("%lld\n",dp[a][b]);
    return 0;
} 

4.地毯

思路

1.三个循环暴力破解,在覆盖的地方+1

2.先二维差分再二维前缀和

代码展示

三个循环暴力破解(不出意外会超时)

#include <stdio.h>
int a[1001][1001] = {0};

int main() {
	int x1, y1, x2, y2;
	int n, m;
	scanf("%d %d", &n, &m);
	for (int i=1;i<=m;i++) {
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		for(int j=x1;j<=x2;j++)
		    for(int k=y1;k<=y2;k++)
		    {
		    	a[j][k]++;
			}
	}
	for (int i=1;i<=n;i++) {
		for (int j=1;j<=n;j++) {
			printf("%d ",a[i][j]);
		}
		printf("\n");
	}
	return 0; 
}

前缀和

#include<stdio.h>

int a[1005][1005]={0};
int main()
{
	int n,m,x1,x2,y1,y2;
	scanf("%d %d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		for(int j=x1;j<=x2;j++)
		{
			a[j][y1]+=1;
			a[j][y2+1]-=1;
		}
	}
	for(int i=1;i<=n;i++)//每一行 
	{
	    for(int j=1;j<=n;j++)//每一列
		{
			a[i][j]+=a[i][j-1];//前缀和 
		}
	}
	//输出操作 
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			-printf("%d ",a[i][j]);
		}
		printf("\n");
	}
	return 0;
}

5.最小新整数

/*给定一个十进制正整数n(0<n<1000000000),每个数位上数字均不为 0。n的位数为 m。
现在从 m 位中删除 k 位 (0<k < m)(0<k<m),求生成的新整数最小为多少?
例如:n=9128456,k=2, 则生成的新整数最小为 12456。

输入格式
第一行 t, 表示有 t 组数据;
接下来 t 行,每一行表示一组测试数据,每组测试数据包含两个数字 n,k。

输出格式
t 行,每行一个数字,表示从 n中删除 k位后得到的最小整数。

Sample Input
2
9128456 2
1444 3
Sample Output
12456
1*/

思路

注意:要删除掉越靠前并且大于等于它后面的那个数

要删去前者比后者大的数,而不是删去最大的数,例如1329 1 那132肯定是要比129大的,如果数字已经是从小到大的了,那就从后往前删直到删除k位为止

代码展示

#include <stdio.h>
#include <string.h>

int main()
{
	char n[50];
	int t,k,len,flag=1;
	scanf("%d",&t);
	while(t--){
		scanf("%s %d",n,&k);
		len=strlen(n);
		for(int i=0;i<k;i++){
			for(int j=0;j<len-1;j++){
				if(n[j]>n[j+1]){
					for(int l=j;l<len-1;l++){//往前移,覆盖掉大的个,相当于删除
						n[l]=n[l+1];
					}
					break;
				}
			}
			len--;//长度每次减1,如果从小到大了,直接删除最后一位
		}
		for(int i=0;i<len;i++){
			printf("%c",n[i]);
		}
		printf("\n");
	}
}

6.宇航员

问题描述:
  宇航员在太空中迷失了方向,在他的起始位置现在建立一个虚拟xyz坐标系,称为绝对坐标系,宇航员正面的方向为x轴正方向,头顶方向为z轴正方向,则宇航员的初始状态如下图所示:


现对六个方向分别标号,x,y,z正方向分别为0,1,2,负方向分别为3,4,5;称它们为绝对方向。宇航员在宇宙中只沿着与绝对坐标系xyz轴平行的方向行走,但是他不知道自己当前绝对坐标和自己面向的绝对方向。

任务描述:
  请根据宇航员对自己在相对方向上移动的描述确定宇航员最终的绝对坐标和面向的绝对方向。对在相对方向上移动的描述及意义如下:
forward x  向前走x米。
back x 先转向后,再走x米。
left x 先转向左,再走x米。
right x 先转向右,再走x米。
up x 先面向上,再走x米。
down x 先面向下,再走x米。
其中向上和向下如下图所示:

Input

第一行一个正整数m,表示测试数据的组数。每组测试数据第一行是一个正整数n(1<=n<=10000)表示宇航员行走的次数,下面n行每行输入一次相对行走,格式如上所述,其中( 1 <= x <= 10000 为正整数)。

Output

对于每组输入数据输出一行,x y z p, 中间用空格隔开,x y z是宇航员的位置的绝对坐标,p是宇航员面向的绝对方向编号(0<=p <=5)。

Sample

InputcopyOutputcopy
1
6
left 10
right 11
up 12
down 13
forward 14
back 15
23 -10 12 3

思路

当向上爬的时候脸的方向和原来头的方向是一样的,所以lian=tou,此时头的方向就是(原来lian的方向+3)%6;

当向下爬的时候头的方向是原来lian的方向,所以tou=lian,此时lian的方向是(原来tou的方向+3)%6;

当向左爬的时候lian的方向是原来zuo手的方向,所以lian=zuo,此时zuo的方向是(原来lian的方向+3)%6;

当向右爬的时候zuo的方向是原来lian的方向,所以zuo=lian,此时lian的方向是(原来zuo的方向+3)%6;

当返回的时候此时zuo的方向就是(原来zuo+3)%6。此时lian的方向就是(原来lian的方向+3)%6;

代码展示

#include<stdio.h>
#include<string.h>

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        char s[10];
        int a;
        int x=0,y=0,z=0;
        int lian=0,zuo=4,tou=2;//原来的方向
        int t;
        for(int i=0;i<n;i++)
        {
            scanf("%s%d",s,&a);
            if(s[0]=='l')
            {
                t=lian;
                lian=zuo;
                zuo=(t+3)%6;
            }
            else if(s[0]=='r')
            {
               t=zuo;
               zuo=lian;
               lian=(t+3)%6;
            }
            else if(s[0]=='u')
            {
                t=lian;
                lian=tou;
                tou=(t+3)%6;
            }
            else if(s[0]=='d')
            {
               t=tou;
               tou=lian;
               lian=(t+3)%6;
            }
            else if(s[0]=='b')
            {
                zuo=(zuo+3)%6;
                lian=(lian+3)%6;
            }
            if(lian==0)
            {
                x+=a;
            }
            else if(lian==1)
            {
                y+=a;
            }
            else if(lian==2)
            {
                z+=a;
            }
            else if(lian==3)
            {
                x-=a;
            }
            else if(lian==4)
            {
                y-=a;
            }
            else if(lian==5)
            {
                z-=a;
            }
        }
        printf("%d %d %d %d\n",x,y,z,lian);
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值