NCST 2018-2019秋季学期个人排位赛(三)
A:养生茶的制作
题目描述:
F学长是一个非常懂得生活的人,平时喜欢制作一些养生的物品,这天F学长正在根据自己的机密配方制作养生茶,其中有两种配料’|‘和’&‘有着严格的添加顺序,必须先添加完’|‘后才能再添加’&’,只有这样两种材料才会融合,其他任何方式的添加都不能使材料融合(也可以完全不加这两种材料),如两种材料不能融合那么就是一种错误的制作方法,现在给你一些制作方法,请你判断这些方法是正确的还是错误的
输入:
一个数n表示有n组数据
每组数据由一个字符串组成,长度小于50
输出:
Yes或No
样例输入:
4
&FXZWD!!!|
|FXZNB!!!&
||NCSTOJ&
|&|&|&|&|&
样例输出:
No
Yes
No
Yes
题目原型:括号匹配,方法用遇到‘|’用栈保存,遇到‘&’时,如果栈空,那么就是非法, 不空就弹出元素,读取完成后判断栈中是否有元素就可以了。
类似于“(())”也就是本题的“||&&”也是正确的答案,因为匹配对应问题的融合
#include<cstring>
#include<cstdio>
#include<stack>
#define rep(i,a,b) for(int i=(a); i<(int)(b);++i)
#define _rep(i,a,b) for(int i=(a);i<=(int)(b);++i)
using namespace std;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
char c[50];
int flag=0;
scanf("%s",c);
stack<char> s;
rep(i,0,strlen(c))
{
if(c[i]=='|')
s.push(c[i]);//入栈
if(c[i]=='&')
{
if(s.empty())
{
flag=1;
printf("No\n");
break;
}
s.pop();//出栈
}
}
if(flag)
continue;
if(s.empty())
printf("Yes\n");
else
printf("No\n");
}
return 0;
}
B:TIO的得分
题目描述:
给出n个由T,I和O组成的字符串,长度小于50,统计所有字符的得分和,每个O的得分为目前连续出现的O的个数,每个I得两分而且不累计,T的得分为0分。
例如:OTITOOOTITOIIT的得分为1+0+2+0+1+2+3+0+2+0+1+2+2+0=16分
输入:
一个数n,表示有n组数据
接下来n行,每行一个字符串
输出:
n行,每行为字符串的得分
样例输入:
1
OTITOOOTITOIIT
样例输出:
16
算法竞赛入门经典P57例题3-1改(UVa1585)
做一个临时变量和总分变量,根据遇到的字母改变就可以
ps:坑了一把else少写了个t=0,结果数据全错了,自责
#include<cstdio>
#include<cstring>
#define rep(i,a,b) for(int i=(a); i<(int)(b);++i)
#define _rep(i,a,b) for(int i=(a);i<=(int)(b);++i)
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
char c[100];
int sum=0,t=0;
scanf("%s",c);
rep(i,0,strlen(c))
{
if(c[i]=='T')
t=0;
else if(c[i]=='O')
{
++t;
sum+=t;
}
else
{
sum+=2;
t=0;
}
}
printf("%d\n",sum);
}
return 0;
}
C:除法
题目描述:
输入正整数n,从小到大输出所有形如 a b c d e f g h i j \frac{abcde}{fghij} fghijabcde=n的表达式,其中a ~ j恰好为数字0 ~ 9的一个排列(可以有前导0), 2 ≤ n ≤ 79 2\le n \le79 2≤n≤79
输入:
n
n为0时表示输入结束
输出:
每种可能的情况,顺序为abcde从小到大输出
形式如: xxxxx/xxxxx=n
如果没有满足的等式,输出There are no solutions
样例输入:
61
62
0
样例输出:
There are no solutions
79546/01283=62
94736/01528=62
算法竞赛入门经典P182例题7-1(UVa725)
认真分析问题下暴力法也是很快的,首先肯定不能用除法来算,所有的除法都要转化为乘法。先来分析分母,因为可以有前导0所以fghij从1234开始循环,然后abcde可以根据n来乘出来,那么循环结束的条件是什么,a-j为0-9的全排列,最多10个数,当两个数的位数加起来超过10位那么循环就可以终止了
ps:这题本来是想出火柴棍 的,因为我不知道啊哈上面有这个题,不过在我就要加题之前yk同学问我这个题,我很是mb,才发现啊哈上有这个题
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int main()
{
int n,mc;
char buf[99];
while(scanf("%d",&n)==1&&n)
{
int cnt=0;
for(int fghij=1234;;++fghij)
{
int abcde=fghij*n;
sprintf(buf,"%05d%05d",abcde,fghij); //%05d,位数不足补0
if(strlen(buf)>10)
break;
sort(buf,buf+10);
int flag=1;
for(int i=0;i<10;++i)//判断0-9是否全部被使用过
if(buf[i]!='0'+i)
flag=0;
if(flag)
{
++cnt;
printf("%05d/%05d=%d\n",abcde,fghij,n);
}
}
if(!cnt)
printf("There are no solutions\n");
}
return 0;
}
D:素数环
题目描述:
输入正整数n,把整数1,2,. . . ,n组成一个环(每组第一个数都是1),使得相邻的两个整数之和均为素数。一个环恰好输出一次。 n ≤ 16 n\le16 n≤16
多组数据,读入EOF结束
输入:
n
输出:
所有情况
第i组数据输出时加上一行Case i:
每一行最后一个数后没有空格
相邻两组数据之间加上空行
祥见样例
样例输入:
6
8
样例输出:
Case 1:
1 4 3 2 5 6
1 6 5 2 3 4
Case 2:
1 2 3 8 5 6 7 4
1 2 5 8 3 4 7 6
1 4 7 6 5 8 3 2
1 6 7 4 3 8 5 2
算法竞赛入门经典P194例题7-4(UVa524)
标准DFS标准DFS标准DFS!!!!!!!!!!!
因为数小,普通的素数判断就可以了,如果数大那么判断素数的时间复杂度也是需要考虑的,这里用的是埃拉托色尼(Eratosthenes)筛法,直接可以标识一个数是不是素数
next_permutation也过不了
#include<cstdio>
#include<math.h>
#include<string.h>
const int maxn=50;
int vis[maxn];
int n,pr[20],book[20];
void prime()
{
int m=sqrt(maxn+0.5);
for(int i=2;i<m;++i)
if(!vis[i])
for(int j=i*i;j<=maxn;j+=i)
vis[j]=1;//代表j不是素数
}
bool isPrime(int n)
{
return vis[n]?false:true;
}
void dfs(int cur)
{
if(cur==n&&isPrime(pr[0]+pr[n-1]))
{
for(int i=0;i<n;++i)
printf("%d%c",pr[i]," \n"[i==n-1]);
return;
}
for(int j=2;j<=n;++j)
{
if(!book[j]&&isPrime(j+pr[cur-1]))//这里剪枝
{
pr[cur]=j;
book[j]=1;
dfs(cur+1);
book[j]=0;
}
}
}
int main()
{
prime();
int tot=0;
while(scanf("%d",&n)==1)
{
memset(book,0,sizeof(book));
if(tot)
printf("\n");
++tot;
printf("Case %d:\n",tot);
pr[0]=1;
dfs(1);
}
return 0;
}
E:F学长的养生茶!!!
题目描述:
F学长刚刚制作好的养生茶被坏同学偷偷的放在了迷宫里的一个地方。迷宫用 N × M N \times M N×M的矩阵表示( N , M ≤ 100 N,M\le 100 N,M≤100)矩阵中的每项可以代表道路(’@’),墙壁(’#’)和高数题(‘x’)
年轻的F学长(‘r’)决定去寻找他的养生茶(‘a’),由于坏同学在路上放了很多高数题,F学长必须解决高数题后才能继续前进,每移动一个位置需要花费1个单位时间,做出一道高数题也需要1个单位时间,同时F学长非常聪明,能做出所有的高数题
给定迷宫,养生茶,F学长和高数题的位置,计算找到养生茶所需要的最短时间
输入:
第一行n,表示有n组数据
每组数据有n,m,代表迷宫行和列
迷宫中’@'代表道路,'a’代表养生茶,'r’代表F学长,‘x’代表高数题,’#'代表墙壁
输出:
如果F学长能找到他的养生茶,输出行动所需最短时间,否则输出Impossible
样例输入:
1
7 8
#@#####@
#@a#@@r@
#@@#x@@@
@@#@@#@#
#@@@##@@
@#@@@@@@
@@@@@@@@
样例输出:
13
改编自 ,这个题可以让你对BFS有更深一点的理解
1
6 5
#####
#@r@#
#@x@#
#@x@#
#@x@#
#@a@#
根据这个数据理解一下路径最短和时间最短,有高数题的点要理解成走两次
#include<queue>
#include<cstdio>
#include<cstring>
#define rep(i,a,b) for(int i=(a); i<(int)(b);++i)
using namespace std;
const int dir[4][2]={0,1,1,0,0,-1,-1,0};
int n,m,book[205][205];
char maze[205][205];
struct point
{
int r,c;
int step;
point(int r=0,int c=0,int step=0):r(r),c(c),step(step){}
};
point tar,start;
void bfs()
{
queue<point> q;
q.push(start);
book[start.r][start.c]=1;
point now;
while(!q.empty())
{
now=q.front();
int now_r=now.r;
int now_c=now.c;
if(now_r==tar.r&&now_c==tar.c)
{
printf("%d\n",now.step);
return;
}
q.pop();
if(maze[now_r][now_c]=='x')//遇到高数题
{
maze[now_r][now_c]='@';//走到这个位置后再解决高数题
q.push(point(now_r,now_c,now.step+1));
}
else
rep(k,0,4)
{
int next_r=now_r+dir[k][0];
int next_c=now_c+dir[k][1];
if(next_r>=0&&next_r<n&&next_c>=0&&next_c<m
&&!book[next_r][next_c]&&maze[next_r][next_c]!='#')
{
book[next_r][next_c]=1;
q.push(point(next_r,next_c,now.step+1));//走到当前位置,是不是高数题无所谓
}
}
}
if(q.empty())
printf("Impossible\n");
}
void input()
{
rep(i,0,n)
{
scanf("%s",maze[i]);
rep(j,0,m)
{
if(maze[i][j]=='a')
tar=point(i,j,0);
if(maze[i][j]=='r')
start=point(i,j,0);
}
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
memset(book,0,sizeof(book));
input();
bfs();
}
return 0;
}
或者直接用优先队列,如果情况更复杂的话上述分情况加点的方法就不是很好实现了,比如我有各种不同的题,每种题需要的时间也不同,那么这样就只能用优先队列了
现在再回看入门经典那个倒水问题才知道有很多的重点和易错点,这题属于倒水问题的入门
又和F学长学一招,检查状态时先检查位置是否越界再检查数组的状态,因为如果位置越界了那么数组可能会访问到非法内存,越严谨越好
#include<queue>
#include<cstdio>
#include<cstring>
#define rep(i,a,b) for(int i=(a); i<(int)(b);++i)
using namespace std;
const int dir[4][2]={0,1,1,0,0,-1,-1,0};
int n,m,book[205][205];
char maze[205][205];
struct point
{
int r,c;
int step;
bool operator < (const point& a)const//用时小的点先出队
{
return step>a.step;
}
point(int r=0,int c=0,int step=0):r(r),c(c),step(step){}
};
point tar,start;
void bfs()
{
priority_queue<point> q;
q.push(start);
book[start.r][start.c]=1;
while(!q.empty())
{
point now=q.top();
int now_r=now.r;
int now_c=now.c;
if(now_r==tar.r&&now_c==tar.c)
{
printf("%d\n",now.step);
return;
}
q.pop();
rep(k,0,4)
{
int next_r=now_r+dir[k][0];
int next_c=now_c+dir[k][1];
if(next_r>=0&&next_r<n&&next_c>=0&&next_c<m
&&!book[next_r][next_c]&&maze[next_r][next_c]!='#')
{
book[next_r][next_c]=1;
if(maze[next_r][next_c]=='x')
q.push(point(next_r,next_c,now.step+2));
else
q.push(point(next_r,next_c,now.step+1));
}
}
}
if(q.empty())
printf("Impossible\n");
}
void input()
{
rep(i,0,n)
{
scanf("%s",maze[i]);
rep(j,0,m)
{
if(maze[i][j]=='a')
tar=point(i,j,0);
if(maze[i][j]=='r')
start=point(i,j,0);
}
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
memset(book,0,sizeof(book));
input();
bfs();
}
return 0;
}