1.迷宫
题目描述
最近,小Y在玩一款迷宫游戏,游戏是在一个n∗ m的网格上进行的,每个格子可能是空地或者障碍物。游戏一开始,玩家控制的角色位于图中的某块空地上。在游戏过程中,玩家可以用上下左右键控制角色向相邻且没有障碍物的格子移动(当然,角色不能移动到地图之外,也不能对角线移动)。游戏的目标是收集地图上出现的星星(每个星星只能收集一次),收集的数量越多分数越高。小Y刚开了一局游戏,假设游戏时间没有限制,他想知道自己最多能收集到多少个星星。
输入
第一行包含两个正整数n和m,表示游戏的地图包含n行m列。
接下来给出一个n×m的字符矩阵,每个字符可能为以下几种:
● #:表示该位置有障碍物
● . (英文句号):表示该位置是空地
● *:表示该位置是空地,且生成了一颗星星
● S :表示该位置是空地,且玩家初始时位于该位置,保证图中有且只有一个S
输出
共一行,包含一个整数,表示最多能收集到多少颗星星
样例输入
4 8 ..#...*. *.#.S#.. ######.. .*..#.*.
样例输出
2
数据范围限制
对于50%的数据,n,m≤40;
对于100%的数据,1≤n,m≤200。
#include<cstdio>
#include<iostream>
using namespace std;
int n,m,ans=0,nx,ny;
char a[500][500];
int xx[4]= {-1,0,1,0},yy[4] {0,1,0,-1}; //上下左右四个方向
int dg(int x,int y);//声明函数
int main() {
freopen("maze.in","r",stdin);
freopen("maze.out","w",stdout);
int i,j,i1,j1;
scanf("%d%d",&n,&m);
for(i=1; i<=n; i++) {
for(j=1; j<=m; j++) {
cin>>a[i][j];//输入
}
}
for(i=1; i<=n; i++) {
for(j=1; j<=m; j++) {
if(a[i][j]=='S') { //判断出生点
dg(i,j);//直接开始递归
break;
}
}
}
printf("%d",ans);//输出最终答案
}
int dg(int x,int y) { //递归函数
int i;
for(i=0; i<=3; i++) {
a[x][y]='#';//走过的就不能再走,标记
nx=x+xx[i];//四个方向
ny=y+yy[i];//四个方向
if(a[nx][ny]!='#'&&nx>=1&&nx<=n&&ny>=1&&ny<=m) { //判断是否出界
if(a[nx][ny]=='*')//得分点就加一下
ans++;
dg(nx,ny);//然后继续宽搜
}
}
}
2.盒子
题目描述
小D在玩堆盒子的游戏,每个盒子有1个强度,代表它上面最多能堆多少个盒子。由于盒子都是一样大的,所以不能在一个盒子上并列放超过一个盒子。现在小D有n个盒子,第i个盒子的强度为xi。小D想知道,如果他要把这些盒子全部堆起来,至少要堆多少堆。
输入
第1行读入一个整数n,代表小D有的盒子个数。
第2行读入n个整数,第i个整数xi表示第i个盒子的强度。
输出
共1行,1个整数表示小D至少要堆多少堆。
样例输入
5 0 2 1 1 2
样例输出
2
数据范围限制
对于20%的数据,n≤10;
对于50%的数据,n≤1000;
对于100%的数据,n≤500000,xi≤1000000000。
#include<iostream>
#include<iomanip>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn=10001;
int n,i,ans,t;
struct cd { //定义队列
int qd;
bool zt;
};
cd a[500010];
bool cmp(cd a1,cd b1) {
return a1.qd<b1.qd;//这里是比大小
}
void input() { //输入输出
cin>>n;
for(i=1; i<=n; i++) {
cin>>a[i].qd;
a[i].zt=1;
}
}
bool comp(cd c[],int p) { //判断函数
int ok1=0;
int o;
for(o=1; o<=p; o++)
if(c[o].zt!=0) { //判断有没有被用过
ok1=1;//有就标记
break;
}
if(ok1==0) return 1;//标记起作用了
else return 0;
}
void work() {
sort(a+1,a+n+1,cmp);
while(comp(a,n)==0) { //当没被用过
ans=0;
for(int i=1; i<=n; i++) {
if(a[i].zt==0) continue;//判断当前书有没有
if(a[i].qd>=ans) { //判断满了没
ans++;//满了就要标记
a[i].zt=0;
}
}
if(ans!=0) t++;//没有标记就记录方案数
}
}
void output() {
cout<<t;//输出
}
int main() {
freopen("box.in","r",stdin);
freopen("box.out","w",stdout);
input();
work();
output(); //函数什么意思不用多说了吧,第一个输入,第二个工作,第三个输出
}
3.四色定理
题目描述
著名的四色定理你一定听说过吧?这可是近代世界三大数学难题之一唷(顺便提上一句,另外两个是费马定理和哥德马赫猜想)。
四色定理的提出来自英国。1852年,毕业于伦敦大学的弗南西斯·格思里(Francis Guthrie)在一家科研单位搞地图着色工作时,发现了一种有趣的现象:“看来,每幅地图都可以用四种颜色着色,使得有共同边界的国家着上不同的颜色。”(注意:只要求有公共边的区域不同色就可以,只有公共顶点的同色也没关系)
这个结论能不能从数学上加以严格证明呢?他和在大学读书的弟弟格里斯决心试一试。兄弟二人为证明这一问题而使用的稿纸已经堆了一大叠,可是研究工作没有进展。
1852年10月23日,他的弟弟就这个问题的证明请教他的老师、著名数学家德·摩尔根,摩尔根也没有能找到解决这个问题的途径,于是写信向自己的好友、著名数学家哈密尔顿爵士请教。哈密尔顿接到摩尔根的信后,对四色问题进行论证。但直到1865年哈密尔顿逝世为止,问题也没有能够解决。
直到1976年,在J. Koch的算法的支持下,美国数学家阿佩尔(Kenneth Appel)与哈肯(Wolfgang Haken)在美国伊利诺斯大学的两台不同的电子计算机上,用了1200个小时,作了100亿判断,才终于完成了四色定理的证明。
你的任务相对那些数学家们来说当然要容易得多:你只要编写一个程序,计算一下在给定的一张有5个区域的地图上,用四种颜色填充不同区域,并保证有公共边的区域不同色的方案数有多少就可以了。
输入
文件第一行是一个整数 n(0<=n<=10),分别表示地图中有公共边的区域的信息数量。
下面n行,每行一对整数,表示对所有区域编号之后,此两个编号的区域是有公共边的。
输出
文件中只有一个整数,表示用四种颜色填充地图的总方案数。注意,在某些方案中,所有四种颜色不必都用到。
样例输入
4 1 2 1 3 1 4 1 5
样例输出
324
数据范围限制
提示
#include<cstdio>
int s,n,x,y,a[10][10],t[10],p;
void bfs(int x) {
if(x==6) { //判断是否列举完可能
s++;//是就答案++
return;
}
for(int i=1; i<=4; ++i) { //枚举所有可能
for(int j=1; j<=x-1; ++j) { //枚举所有可能
if(a[x][j]==1&&t[j]==i) { //判断是否相连 和 同色
p=1;//连就标记一下
break;//直接退出
}
}
if(p==1) { //这里是清零的作用
p=0;//这里是清零的作用
continue;//这里是清零的作用
}
t[x]=i;//这里是记忆化数组的作用
bfs(x+1);//搜索
}
}
int main() {
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
scanf("%d",&n);//输入n
for(int i=1; i<=n; ++i) {
scanf("%d%d",&x,&y);//输入每个数
a[x][y]=1;//标记关系
a[y][x]=1;//标记关系
}
bfs(1);//开始搜索
printf("%d",s);//搜索完输出
}
4.数字分组
题目描述
小明的数学计算能力超强,常常在同学们面前表面得很骄傲。数学科代表实在看不下去了,决定出道很麻烦的题,好好“折磨”他一下。
数学科代表决定给他一些数,让他分组。从第一个数开始分组,且每组必须是连续的一段数,要求每组和相等,问每组和最小可以是多少。(当然这些数一定可以被分组,大不了直接分成一组。)
输入
第一行为一个数N
第二行为N个整数(每个数均小于等于1000),两个数间用空格隔开。
输出
一行,最小的和
样例输入
6 2 5 1 3 3 7
样例输出
7
数据范围限制
1 n = 10
2 n = 100
3 n = 1000
4 n = 200000
5 n = 200000
6 n = 1000000
7 n = 1000000
8 n = 1000000
9 n = 1000000
10 n = 1000000
提示
分成三组(2,5) (1,3,3) (7) 和为7,不存在比7更小的和。
#include<bits/stdc++.h>
using namespace std;
int a[1000005],b[1000005],n;
long long int k=0;
bool rechecking/*查重函数*/(int da) {
int sum=0;
for(int j=1; j<=n; j++) {
sum+=a[j];//当前数累加
if(sum>da) { //大于一定不行
return false;//直接返回不行
}
if(sum==da) { //等于就让他继续累加下去,直到n为止
sum=0;//清零
}
}
return true;//最终一定是可行的
}
int uu=0;
int main() {
freopen("d.in","r",stdin);
freopen("d.out","w",stdout);
cin>>n;//输入n
for(register int i=1; i<=n; i++) {
scanf("%d",&a[i]);//输入各个数
k+=a[i];//求和
if(uu<a[i])uu=a[i];//求最大值
}
for(long long int i=uu; i<=k/2/*次大约数是K除二*/; i++) { //因为最小能组成和的数是其中的最大值
//例如 2 5 6 1 2 5,最小为7,7>6
//或 2 3 5 1 4,最小为5,5=5
//所以得出最小值 >= 最大值
if(k%i==0) { //判断是否为约数
if(rechecking(i)==true) { //判断是否能被被构成
cout<<i;//直接输出
return 0;//节省时间复杂度 :)
}
}
}
cout<<k;//要都不能构成,就只有 K了
}
没了