1.字符串的旋转问题
咕咕东是个贪玩的孩子,有一天,他从上古遗迹中得到了一个神奇的圆环。
这个圆环由字母表组成首尾相接的环,环上有一个指针,最初指向字母a。
咕咕东每次可以顺时针或者逆时针旋转一格。例如,a顺时针旋转到z,逆时针旋转到b。
咕咕东手里有一个字符串,但是他太笨了,所以他来请求你的帮助,问最少需要转多次。
对于这个问题的分析而言,我们可以简单的将其视为贪心算法,每次旋转的过程中,旋转的格数为 x 或 26-x ,我每一次都选择这两个数中小的那个。对于每次的字符处理而言,每次的旋转都相当于一个新的开始。因而不停的选择并累加两个数中较小的那个即可。
#include <iostream>
#include <cmath>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
char test[10001];
int main()
{
int now=0,sum=0;
cin>>test;
int n=strlen(test); // n为字符串中字符的个数
for(int i=0;i<n;i++)
{
int t=test[i]-'a';
int size=t-now;
if(size<0)
size=-1*size;
int count=min(size,26-size);
sum=sum+count;
now=t;
}
cout<<sum;
}
2.特定购买方式的判断问题
一共有n天,然后每天需要买恰好ai个披萨,对于每天披萨的购买只有两种方式,要么一次买两个披萨,要么一次为今天买一个披萨同时为明天也买一个披萨,不能有其余任何的购买方式,且这两种购买方式可以使用无限次数,问是否每天都能恰好买到ai个。
思路:显然对于第i天的披萨,如果ai是偶数,则直接用第一种购买方式,因为这显然合法且对后面不产生影响,若ai是奇数,则应该先用第一种购买方式买到只剩一个,然后再用第二种购买方式。因此用sum标记当天有的券,且sum的取值只能是0或1,则当天购买的数目为ai-sum。假如购买数目为负,不合法并且结束程序,否则运行到最后之后判断sum是否为0,不为0则表明不合法。
#include <iostream>
using namespace std;
int main()
{
int sum=0,n;
// n=-1%2;
// cout<<n; 此时的输出结果为 -1;
cin>>n;
while(n>0)
{
int a;
cin>>a;
if((a-sum)%2==1) sum=1; //一共三种情况,我将两种情况进行了统一
else if((a-sum)%2==-1)
{
cout<<"NO";
exit(0);
}
//else if((a-sum)%2==0) sum=0;
else sum=0;
n--;
}
if(sum==0) cout<<"YES";
else cout<<"NO";
}
3.宇宙射线问题
单纯的递归会运行超时。
注意set容器与迭代器的使用,利用对称的思想使得有路径才会生成。
在讲师上课的时候,讲了一种方法为记忆化的广度优先搜索。那个我认为好理解也好实现。对于这个题目而言,每分裂一次,我们都进行遍历的话,很明显会超时。我利用无记忆递归进行实现时,在进行第五组测试时就会超时。
因而,我们除了进行记忆标记外。对于每次的分裂而言,我们只统计一条路径。然后这条路径到头后,我们利用8个方向的几何关系将该分支的相应对称分支进行标记。这样的话就实现了类似于记忆化搜索的效果。通过非重复化的标记访问,降低了时间复杂度。
#include<iostream>
#include<stdio.h>
#include<cmath>
#include<set>
using namespace std;
int *a;
int dx[8]={0,1,1,1,0,-1,-1,-1};
int dy[8]={1,1,0,-1,-1,-1,0,1};
struct node
{
int x,y;
int d;
node()
{
x=0, y=0;
}
node(int x1, int y1)
{
x = x1;
y = y1;
}
};
bool operator <(const node &m,const node &n)
{
if(m.x!=n.x)
return m.x<n.x;
else
return m.y<n.y;
}
bool operator ==(const node &m,const node &n)
{
return m.x==n.x&&m.y==n.y;
}
set<node> way;
void number(int len, int n, int dir, const node& pos)
{
if(len>=n) //len分裂次数,a[len],该次分裂长度
return;
int x = pos.x, y = pos.y;
x = x + dx[dir]*a[len];
y = y + dy[dir]*a[len];
node pos1(x,y);
int dir1 = (dir+1)%8;
number(len+1, n, dir1, pos1);
x = pos.x, y = pos.y;
for(int i=0;i<a[len];i++)
{
x = x + dx[dir];
y = y + dy[dir];
node pos2(x,y);
way.insert(pos2);
}
if(len!=0)//对称
{
for(set<node>::iterator it=way.begin();it!=way.end();it++)
{//将点对称
node now;
if(dir==0||dir==4)
{
now.x=pos.x+pos.y-it->y;
now.y=pos.x+pos.y-it->x;
}
else if(dir==1||dir==5)
{
now.x=2*pos.x-it->x;
now.y=it->y;
}
else if(dir==2||dir==6)
{
now.x=it->y-pos.y+pos.x;
now.y=it->x+pos.y-pos.x;
}
else if(dir==3||dir==7)
{
now.x=it->x;
now.y=2*pos.y-it->y;
}
way.insert(now);
}
}
}
int main()
{
int t;
cin>>t;
a = new int[t];
node now(0,0);
for(int i=0;i<t;i++)
cin>>a[i];
number( 0, t, 0, now);
cout<<way.size()<<endl;
return 0;
}