目录
A:判决素数个数【水题】
B:编码字符串(string)【水题】
C:岛屿周长(matrix)【深搜或者找规律】
D:Safecracker【深搜或者暴力不水】
E:怪盗基德的滑翔翼【动态规划】
F:Full Tank?【图论最短路/BFS+优先队列】
G:实现堆结构
H:Subway(迪杰斯特拉算法)
I:C Looooops
J:Captain Q's Treasure
A:判决素数个数【水题】
#include<iostream>
using namespace std;
int sum;
void sushu(int x){
if(x==1) return;
for(int j=2;j<=x/2;j++){
if(x%j==0) return;
}
sum++;
}
int main(){
int X,Y;
cin>>X>>Y;
if(X>Y) swap(X,Y);
for(int i=X;i<=Y;i++){
sushu(i);
}
cout<<sum;
}
B:编码字符串(string)【水题】
#include<iostream>
using namespace std;
int main(){
string ch;
int sum=1;
cin>>ch;
// cout<<(int)'A'<<(int)'Z'; 65 90
// cout<<(int)'a'<<(int)'z'; 97 122
int len=ch.length();
for(int i=0;i<len;i++){
if((int)ch[i]>=65&&(int)ch[i]<=90)
ch[i]=ch[i]+32;
}
for(int i=0;i<len;i++){
if(ch[i]==ch[i+1]) sum++;
else {
cout<<"("<<ch[i]<<","<<sum<<")";
sum=1;
}
}
}
这题挺简单的,就判断就行了,别做复杂了
C:岛屿周长(matrix)【深搜或者找规律】
方法一:深搜
这里的关键在于要把数组全部置为0,因为周长计算的是陆地和海洋相连的地方,也就是说,四周只有有一个海洋(表示为0),周长就可以+1;所以对于第一行、最后一行以及第一列和最后一列,都需要判断输入数组四周的数值,这也是主函数里为什么从1开始存储而不是0的原因。
#include <stdio.h>
#include <string.h>
const int MAXN=110;
int mapp[MAXN][MAXN]; //记录岛屿的信息,1表示陆地,0表示海洋
int vis[MAXN][MAXN]; //表示已经访问过
int dir[4][2]={0,1,1,0,0,-1,-1,0};
int n,m,cnt=0;
int dfs(int ni,int nj){
if(vis[ni][nj]==1){
return 0;
}
if(vis[ni][nj]==0&&mapp[ni][nj]==1){
vis[ni][nj]=1;
}
if(mapp[ni][nj]==0){
return 1;
}
for(int i=0;i<4;i++){
int ti=ni+dir[i][0];
int tj=nj+dir[i][1];
cnt+=dfs(ti,tj);
}
return 0;
}
int main()
{
memset(vis,0,sizeof(vis));
memset(mapp,0,sizeof(mapp));
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&mapp[i][j]);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
dfs(i,j);
}
}
printf("%d",cnt);
return 0;
}
方法二:找规律,原理同上,只不过用循环表示了出来,其实没有必要深搜做,除非是为了时间复杂度,因为两层for循环的时间复杂度到n方了
#include<iostream>
using namespace std;
int main(){
int n, m,ans=0;
int a[103][103] = {0};//二维矩阵存储
cin >> n >> m;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
cin >> a[i][j];
for (int i = 0; i < n; i++)//处理每一个数值为1的点,相邻如果不同,则结果加1
{
for (int j = 0; j < m; j++)
{
if (a[i][j] == 0) { continue; }
if (a[i - 1][j] == 0) { ans++; }
if (a[i + 1][j] == 0) { ans++; }
if (a[i][j - 1] == 0) { ans++; }
if (a[i][j + 1] == 0) { ans++; }
}
}
cout << ans;
return 0;
}
D:Safecracker【深搜或者暴力不水】
POJ1248可以测试,思路就是先把数组按照字典序从大到小排列,然后进行全排列不断尝试是否可行,第一组可行的数据就是字典序最大的数据,直接输出并且结束程序即可
// 可以用strcmp()函数来判断字符串的字典序排序
// 希望得到字典序最大的解 —— 从大到小排序,得到第一个解即返回
// 从小到大排序,一直遍历得到最后一个解返回
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
int target;
char str[30];
char ans[10];
int flag = 0; // 判断是否存在解的标志
int change(char a)
{
int t = a - 'A' + 1;
return t;
}
bool judge(int a, int b, int c, int d, int e)
{
if(a-b*b+c*c*c-d*d*d*d+e*e*e*e*e == target)
{
return true;
}
else
{
return false;
}
}
void code(int len)
{
for(int a=0; a<len; a++)
{
for(int b=0; b<len; b++)
{
if(b == a)
{
continue;
}
for(int c=0; c<len; c++)
{
if(c==b || c==a)
{
continue;
}
for(int d=0; d<len; d++)
{
if(d==c || d==b || d==a)
{
continue;
}
for(int e=0; e<len; e++)
{
if(e==d || e==c || e==b || e==a)
{
continue;
}
if(judge(change(str[a]), change(str[b]), change(str[c]), change(str[d]), change(str[e])) == true)
{
flag = 1;
ans[0] = str[a];
ans[1] = str[b];
ans[2] = str[c];
ans[3] = str[d];
ans[4] = str[e];
return ; // 从大到小遍历,得到的第一个解便是字典序最大的解
}
}
}
}
}
}
}
void print()
{
if(flag == 0)
{
printf("no solution\n");
}
else
{
for(int i=0; i<5; i++)
{
printf("%c", ans[i]);
}
printf("\n");
}
}
bool cmp(char a, char b)
{
return a > b;
}
int main()
{
// freopen("input.txt","r",stdin);
while(scanf("%d %s", &target, str)!=EOF)
{
flag = 0; // 每次判断前要把上次的标志恢复
if(target==0 && strcmp(str,"END")==0)
{
break;
}
int len = strlen(str);
// 当从小往大查询,查询的数依次增大,最终得到的结果必定是字典序号和最大的
// 当从大往小查询,得到的第一个解则是字典序号和最大的
sort(str, str+len, cmp); // 从大到小排序
code(len);
print();
}
// fclose(stdin);
return 0;
}
方法二:深搜
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
int target;
char str[30];
char ans[10], temp[10];
int len;
int flag = 0; // 判断是否存在解的标志
int visit[30] = {0}; // 记录字符串每位被访问过与否
int change(char a)
{
int t = a - 'A' + 1;
return t;
}
bool judge(int a, int b, int c, int d, int e)
{
if(a-b*b+c*c*c-d*d*d*d+e*e*e*e*e == target)
{
return true;
}
else
{
return false;
}
}
// DFS搜索到最后得到的是最后一组解,前边的解都会被覆盖
void DFS(int depth)
{
if(depth >= 5) // 死胡同——搜索5个数,深度从0~4,也就是说深度为5时开始判断本次搜索成功与否
{ // 加flag==0则从大到小排序,不加flag==0则从小到大排序
if(judge(change(temp[0]),change(temp[1]),change(temp[2]),change(temp[3]),change(temp[4]))==true && flag==0) // 存在解
{ // flag==0 得到第一组解后不再对解更新,第一组解是字典序最大,如果不加这个条件,则最后得到的是最后一组解
flag = 1;
strcpy(ans, temp); // 将正确的解存入ans,第一次存入的即为字典序最大
}
return ; // 从大到小排序、搜索,得到的第一组解便是字典序最大的解
}
// 岔路口——按层次进行探索,探索完成进行回溯
for(int i=0; i<len; i++)
{
if(visit[i] == 0) // 未访问过的字符
{
temp[depth] = str[i]; // temp临时记录路径
visit[i] = 1; // 记录已被访问过
DFS(depth+1); // 向下一层搜索
visit[i] = 0; // 回溯,恢复该位置的访问记录
}
}
}
void print()
{
if(flag == 0)
{
printf("no solution\n");
}
else
{
for(int i=0; i<5; i++)
{
printf("%c", ans[i]);
}
printf("\n");
}
}
bool cmp(char a, char b)
{
return a > b;
}
int main()
{
// freopen("input.txt","r",stdin);
while(scanf("%d %s", &target, str) != EOF)
{
flag = 0;
if(target==0 && strcmp(str,"END")==0)
{
break;
}
len = strlen(str);
sort(str, str+len, cmp); // 从大到小排序
DFS(0); // 搜索
print();
}
// fclose(stdin);
return 0;
}
E:怪盗基德的滑翔翼【动态规划】
思路分析
本题是一道“最长递增/递减子序列”模板题,利用动态规划来解决。但因为可以向两个方向移动,所以要从左向右、从右向左分别求解最长递减子序列。注:从右向左最长递减子序列 <=> 从左向右最长递增子序列。
因而本题只需要分别求出最长和最短递减子序列,二者中的较大值即为本题结果。
动态规划
设置dp[i]表示以字符S[i]为结尾的最长子串长度,初始化dp[i]=1。
遍历整个字符串,对于每个S[i],遍历S[j] (j<i) ,如果S[i]与S[j]间满足递增或递减条件,且以S[j]为结尾的子序列加上S[i]得到的dp值大于当前以S[i]为结尾子序列的dp值,即dp[j]+1>dp[i],则更新dp[i]=dp[j]+1。输出结果取最大的dp值。
E:怪盗基德的滑翔翼
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn = 110;
int tower[maxn];
int dp_d[maxn]; // 以tower[i]为结尾的最长递减子序列长度为dp_d[i];
int dp_i[maxn]; // 以tower[i]为结尾的最长递减子序列长度为dp_i[i];
int LDS(int len) // 最长递减子序列
{
int ans = -1;
for(int i=0; i<len; i++) // 以tower[i]为结尾的串
{
dp_d[i] = 1; // 先初始化
for(int j=0; j<i; j++)
{
if(tower[j]>=tower[i] && dp_d[j]+1>dp_d[i])
{
dp_d[i] = dp_d[j] + 1;
}
}
ans = max(ans, dp_d[i]);
}
return ans;
}
int LIS(int len) // 最长递增子序列
{
int ans = -1;
for(int i=0; i<len; i++)
{
dp_i[i] = 1;
for(int j=0; j<i; j++)
{
if(tower[j]<=tower[i] && dp_i[j]+1>dp_i[i])
{
dp_i[i] = dp_i[j] + 1;
}
}
ans = max(ans, dp_i[i]);
}
return ans;
}
int main()
{
// freopen("input.txt", "r", stdin);
int k;
scanf("%d", &k);
int n;
for(int i=0; i<k; i++)
{
scanf("%d", &n);
for(int j=0; j<n; j++)
{
scanf("%d", &tower[j]);
}
// 反向最长递减子序列=正向最长递增子序列
int ans_i = LIS(n); // 反向跳跃等价于 最长递增子序列
int ans_d = LDS(n); // 正向跳跃等价于 最长递减子序列
int ans = max(ans_i, ans_d); // 结果为二者中最大值
printf("%d\n", ans);
}
// fclose(stdin);
return 0;
}
F:Full Tank?【图论最短路/BFS+优先队列】
参考:Full Tank?(BFS+优先队列)
G:实现堆结构
POJ 4078可以测试
方法一:堆结构的基本操作
//实现堆的基本操作
#include<iostream>
#include<vector>
using namespace std;
int N,ans=0;
vector<int>val;
void DownHeap(){//堆纠正
int k=1;
while(2*k<=ans){//如果有左孩子 k的左孩子为2k 右孩子为2k+1
int j=2*k;//指向左孩子
if(j<ans&&val[j]>val[j+1])//k的左右孩子进行相比较
j=j+1;//若右孩子小于左孩子 j指向右孩子
if(val[k]<=val[j])//比较小的孩子小
break;
else//说明父亲节点k要比孩子j大 需要交换
swap(val[k],val[j]);//交换位置
k=j;//k交换到新的位置,继续向下比较,一直沉到底部
}
}
void CreateHeap(int n){//建堆
val[++ans]=n;
int i=ans;
while(1){
if(i<=1)
break;
if(val[i/2]>val[i])
swap(val[i/2],val[i]);//进行互换
i=i/2;
}
}
int main(){
cin>>N;
val.resize(N+2);
int type,num;
for(int i=0;i<N;i++){
cin>>type;
if(type==1){
cin>>num;
CreateHeap(num);
}
else{
cout<<val[1]<<endl;//最小值 小顶堆 最小值在第一个
swap(val[1],val[ans]);
--ans;//交换之后 长度减一 相当于删除这个最小的元素 在赋值的话会把原来ans位置的元素覆盖掉 不影响后面程序执行
DownHeap();//进行堆调整
}
}
return 0;
}
方法二:优先队列
#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
priority_queue<int, vector<int>, greater<int> > q; // 小堆顶结构
int main(){
int t;
scanf("%d", &t);
for(int i=0; i<t; i++){
int n, type;
scanf("%d", &n);
for(int j=0; j<n; j++){
scanf("%d", &type);
if(type == 1){
int u;
scanf("%d", &u);
q.push(u);
}
if(type == 2){
printf("%d\n", q.top());
q.pop();
}
}
}
return 0;
}
H:Subway(迪杰斯特拉算法)
2017计算机学科夏令营上机考试H:Subway(图的构建+Dijkstra)
I:C Looooops
POJ 2115
#include<cstdio>
#include<cctype>
#include<iostream>
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b){
return b?gcd(b,a%b):a;
}
void exgcd(ll a,ll b,ll &x,ll &y){
if(b==0){
x=1;y=0;
return;
}
exgcd(b,a%b,x,y);
ll temp;
temp=x;
x=y;
y=temp-(a/b)*y;
return;
}
int main(){
ll A,B,C,k;
while(cin>>A>>B>>C>>k){
if(A==B&&B==C&&C==k&&A==0)return 0;
ll x,y;
ll a=C,b=(ll)1<<k,c=B-A;
if(!c){
printf("0\n");
continue;
}
ll g=gcd(a,b);
if(c%g){
printf("FOREVER\n");
continue;
}
a/=g;b/=g;c/=g;
exgcd(a,b,x,y);
x=(x%b*c%b+b)%b;
printf("%lld\n",x);
}
return 0;
}
C Looooops (扩展欧几里得算法)
J:Captain Q's Treasure
自觉放弃好吧