算法训练 字符串变换
问题描述
相信经过这个学期的编程训练,大家对于字符串的操作已经掌握的相当熟练了。今天,徐老师想测试一下大家对于字符串操作的掌握情况。徐老师自己定义了1,2,3,4,5这5个参数分别指代不同的5种字符串操作,你需要根据传入的参数,按照徐老师的规定,对输入字符串进行格式转化。
徐老师指定的操作如下:
1 表示全部转化为大写字母输出,如abC 变成 ABC
2 表示全部转换为小写字母输出,如abC变成abc
3 表示将字符串整个逆序输出,如 abc 变成 cba
4 表示将字符串中对应的大写字母转换为小写字母,而将其中的小写字母转化为大写字母输出,如 abC变成ABc
5表示将全部转换为小写字母,并将其中所有的连续子串转换为对应的缩写形式输出,比如abcD 转换为a-d,其次,-至少代表1个字母,既如果是ab,则不需要转换为缩写形式。
输入格式
一共一行,分别是指代对应操作的数字和字符串,两者以空格分隔,字符串全部由英文字母组成
输出格式
输出根据上述规则转换后对应的字符串
样例输入
5 ABcdEE
样例输出
a-ee
数据规模和约定
输入字符串长度最长为200。
模拟题,直接贴代码,注意s跟i的含义。
#include <bits/stdc++.h>
using namespace std;
int main(){
int tp,top[1111];
char st[1111];
scanf("%d %s",&tp,st);
if(tp==1){
for(int i=0;i<strlen(st);i++){
if('a'<=st[i]&&st[i]<='z') putchar(st[i]-32);
else putchar(st[i]);
}
puts("");
}
if(tp==2){
for(int i=0;i<strlen(st);i++){
if('A'<=st[i]&&st[i]<='Z') putchar(st[i]+32);
else putchar(st[i]);
}
puts("");
}
if(tp==3){
for(int i=strlen(st)-1;i>=0;i--) putchar(st[i]);
puts("");
}
if(tp==4){
for(int i=0;i<strlen(st);i++){
if('A'<=st[i]&&st[i]<='Z') putchar(st[i]+32);
if('a'<=st[i]&&st[i]<='z') putchar(st[i]-32);
}
puts("");
}
if(tp==5){
for(int i=0;i<strlen(st);i++)if('A'<=st[i]&&st[i]<='Z') st[i]+=32;
int s=0;
while(s<strlen(st)){
int i;
for(i=s+1;i<strlen(st);i++)
if(st[i]!=st[i-1]+1) break;
i--;
if(i==s||i==s+1){
putchar(st[s]);
s++;
continue;
}
else{
putchar(st[s]);
putchar('-');
putchar(st[i]);
s=i+1;
}
}
}
return 0;
}
算法提高 快速幂
求 A^B%P
二分快速幂
#include <cstdio>
#include <iostream>
using namespace std;
long long a,b,p;
long long bigpow(long long x, long long y){
long long ret = 1;
long long tmp = x;
while (y > 0){
if (y & 1) ret = (ret%p)*(tmp%p)%p;
y >>= 1;
tmp = (tmp%p) * (tmp%p) % p;
}
return ret;
}
int main(){
cin >>a>>b>>p;
cout<<bigpow(a,b)<<endl;
return 0;
}
算法提高 线段和点
问题描述
有n个点和m个区间,点和区间的端点全部是整数,对于点a和区间[b,c],若a>=b且a<=c,称点a满足区间[b,c]。
求最小的点的子集,使得所有区间都被满足。
贪心??????
每次选能覆盖最多区间的点。
#include <bits/stdc++.h>
using namespace std;
bool dian[50009];
bool v[11111];
struct node{
int l,r;
}sec[11111];
bool cmp(node t1,node t2){
return ((t1.l<t2.l)||(t1.l==t2.l)&&(t1.r<t2.r));
}
int main(){
int n,m,x;
scanf("%d%d",&n,&m);
memset(dian,0,sizeof(dian));
memset(v,0,sizeof(v));
for(int i=1;i<=n;i++){
scanf("%d",&x);
dian[x]=1;
}
for(int i=1;i<=m;i++){
scanf("%d%d",&sec[i].l,&sec[i].r);
}
sort(sec+1,sec+1+m,cmp);
int ans=0,E;
for(int i=1;i<=m;i++){
int mx=-INT_MAX;
if(!v[i]){
for(int j=sec[i].l;j<=sec[i].r;j++){
if(dian[j]){
int tot=0;
for(int k=i+1;k<=m;k++){
if(sec[k].l<=j&&j<=sec[k].r){
tot++;
}
else break;
}
if(tot>mx){
mx=tot;
E=j;
}
}
}
ans++;
for(int k=i+1;k<=m;k++){
if(sec[k].l<=E&&E<=sec[k].r){
v[k]=1;
}
else break;
}
}
}
printf("%d\n",ans);
return 0;
}
算法提高 理财计划
#include <iostream>
#include <cstdio>
using namespace std;
int main(){
int k, n;
double p;
cin>>k>>n>>p;
double ans = 0;
for(int i=1;i<=n;i++) {
ans=ans+k;
ans=ans*(1+p);
}
printf("%.2f", ans-n*k);
return 0;
}
算法提高 超级玛丽
F[n]=F[n-1]+F[n-2],F[n]=0,(n为陷阱)
# include <stdio.h>
# include <string.h>
int n, m;
int dp[50],flag[50];
int g[50];
int main(){
int i, j, k, num, flage;
scanf("%d%d", &n, &m);
for(int i=1;i<=m;i++){
int x;
scanf("%d",&x);
flag[x]++;
}
if(flag[1]==0) dp[1]=1;
if(flag[2]==0) dp[2]=1;
for(int i=3;i<=n;i++){
if(flag[i]==0) dp[i]=dp[i-1]+dp[i-2];
else dp[i]=0;
}
printf("%d\n",dp[n]);
return 0;
}
算法训练 连续正整数的和
#include <cstdio>
using namespace std;
int main(){
int s;
scanf("%d",&s);
for(int i=1;i<=s;i++){
for(int j=i+1;j<=s;j++){
int sum = (i+j)*(j-i+1)/2;
if(sum==s) printf("%d %d\n",i,j);
if(sum>s) break;
}
}
return 0;
}
算法提高 盾神与砝码称重
n个砝码,看看能不能称出m的重量。
搜索题,裸搜复杂度O(3^n),亲测50分
#include <bits/stdc++.h>
#define base 1000000
using namespace std;
int w[25];
int info[11];
int n,m;
bool f0[2000001],f1[2000001];
int dfs(int noww,int id){
if(!noww) return 1;
if(id==n+1&&noww!=0){
return 0;
}
return dfs(noww-w[id],id+1)||dfs(noww,id+1)||dfs(noww+w[id],id+1);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
sort(w+1,w+1+n);
for(int i=1;i<=m;i++){
int x;
scanf("%d",&x);
puts(dfs(x,1)?"YES":"NO");
}
return 0;
}
优化,将砝码从小到大排序,求一个前缀和,从大的砝码开始取,若剩下的砝码质量不及当前质量的绝对值,return 0。
#include <bits/stdc++.h>
using namespace std;
int w[25];
int info[11];
int n,m;
int sum[25];
inline int dfs(int noww,int id){
if(!noww) return 1;
if(id==0&&noww!=0){
return 0;
}
if(abs(noww)>sum[id]) return 0;
for (;id>=1;id--){
if (dfs(noww-w[id], id-1)||dfs(noww+w[id], id-1)){
return 1;
}
}
return 0;
}
inline bool cmp(int x,int y){return x<y;}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
sort(w+1,w+1+n,cmp);
for(int i=1;i<=n;i++) sum[i]=sum[i-1]+w[i];
for(int i=1;i<=m;i++){
int x;
scanf("%d",&x);
puts(dfs(x,n)?"YES":"NO");
}
return 0;
}
优化2:每次做到一个质量然后hash,此种做法80分,这里就不贴了。
算法训练 开心的金明
dp,经典老题。
01背包
#include <bits/stdc++.h>
using namespace std;
int N, m, v[30005], p[33];
int f[30005];
int main(){
int ans;
scanf("%d%d", &N, &m);
for(int i=1; i<=m; i++){
scanf("%d%d", &v[i], &p[i]);
}
for(int i=1;i<=m;i++)
for(int j=N;j>=0;j--)
if(j>=v[i]) f[j] = max(f[j],f[j-v[i]]+v[i]*p[i]);
ans=-INT_MAX;
for(int i=N; i>=0; i--){
ans = max(f[i], ans);
}
printf("%d\n", ans);
return 0;
}
历届试题 剪格子
问题描述
如下图所示,3 x 3 的格子中填写了一些整数。
+--*--+--+
|10* 1|52|
+--****--+
|20|30* 1|
*******--+
| 1| 2| 3|
+--+--+--+
我们沿着图中的星号线剪开,得到两个部分,每个部分的数字和都是60。
本题的要求就是请你编程判定:对给定的m x n 的格子中的整数,是否可以分割为两个部分,使得这两个区域的数字和相等。
如果存在多种解答,请输出包含左上角格子的那个区域包含的格子的最小数目。
如果无法分割,则输出 0。
dfs裸搜
判断是否合法的时候麻烦点,要再写个dfs统计联通块,checkb中,f1为已取格子数,f2为未取格子数,随便找一个未取的,看看能不能遍历完。f1+f2==n*m则符合要求。
#include <bits/stdc++.h>
using namespace std;
int g[11][11];
int v[13][13];
int v2[13][13];
int range[13][13];
const int dx[]={0,1,-1,0,0};
const int dy[]={0,0,0,-1,1};
int n,m,s=0,mn=INT_MAX;
int find(int x, int y, int id){
if(v2[x][y]) return 0;
int tot=0;
if(range[x][y]==0) return 0;
if(v[x][y]!=id) return 0;
if(v[x][y]==id) tot++;
v2[x][y]=1;
for(int i=1;i<=4;i++){
tot += find(x+dx[i],y+dy[i],id);
}
return tot;
}
bool checkb(int x,int y){
memset(v2,0,sizeof(v2));
int f1=find(x,y,1);
int f2;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
if(v[i][j]==1) continue;
memset(v2,0,sizeof(v2));
f2=find(i,j,0);
return f1+f2==m*n;
}
}
bool check(int i,int j){
if(!range[i][j]) return 0;
v[i][j]=1;
bool pan=checkb(i,j);
v[i][j]=0;
return pan;
}
int dfs(int i,int j,int dep,int s){
if(s<g[i][j]) return 0;
if(v[i][j]) return 0;
if(check(i,j)==0) return 0;
if(s==g[i][j]){
if(dep<mn) mn=dep;
return 0;
}
v[i][j]=1;
for(int cnt=1;cnt<=4;cnt++){
dfs(i+dx[cnt],j+dy[cnt],dep+1,s-g[i][j]);
}
v[i][j]=0;
}
int main(){
scanf("%d%d",&m,&n);
memset(v,0,sizeof(v));
memset(range,0,sizeof(range));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
scanf("%d",&g[i][j]);
s+=g[i][j];
range[i][j]=1;
}
if(s%2==1){
puts("0");
return 0;
}
s/=2;
dfs(1,1,0,s);
printf("%d\n",mn+1);
return 0;
}
历届试题 九宫重排
经典的八数码问题。宽搜裸的话不知道能拿多少分。
多种方法求解八数码问题links
这边说一个在网上看到的结论。
对于八数码问题,有解的话,步数一定是在32步以内的。如果bfs层数超过32,直接-1即可
还有,百度如何正确有效地使用hash。
贴上一份代码。
#include <bits/stdc++.h>
using namespace std;
const int dx[] = {-1, 1, 0, 0};
const int dy[] = {0, 0, -1, 1};
int htable[10007],f,r;
int next[444444];
int Q[444444][9];
int zeros[444444];
int vis[444444];
int purpose[9];
int pre[444444];
int hash(int pos){
int num = 0;
for(int i = 0; i < 9; i++){
num = num*10+Q[pos][i];
num%=10007;
}
return num;
}
bool insert(int pos){
int num=hash(pos);
for(int n=htable[num];n!=-1;n=next[n]){
if(memcmp(Q[n],Q[pos],sizeof(Q[pos]))==0)
return false;
}
next[pos]=htable[num];
htable[num]=pos;
return true;
}
int bfs(){
pre[0]=-1;
while(f<r){
int *now = Q[f++];
if(memcmp(now, purpose, sizeof(purpose)) == 0)
return f-1;
int zx = zeros[f-1]/3;
int zy = zeros[f-1]%3;
for(int i = 0; i < 4; i++){
int nowx = zx+dx[i];
int nowy = zy+dy[i];
if(nowx < 0 || nowx >=3 || nowy < 0 || nowy >= 3)
continue;
int (*next)[3] = (int (*)[3])Q[r++];
memcpy((int *)next, now, sizeof(int)*9);
next[zx][zy] = next[nowx][nowy];
next[nowx][nowy] = 0;
zeros[r-1] = nowx*3+nowy;
pre[r-1] = f-1;
if(!insert(r-1))
r--;
}
}
return -1;
}
int main(){
memset(htable, -1, sizeof(htable));
f=0,r=0;
for(int i = 0; i < 9; i++){
char ch;
ch=getchar();
if(ch == '.') {
Q[0][i] = 0;
zeros[0] = i;
}
else
Q[0][i] = ch-'0';
}
getchar();
r++;
for(int i = 0; i < 9; i++){
char ch;
ch=getchar();
if(ch=='.') purpose[i]=0;
else purpose[i]=ch-'0';
}
int tot=0;
for(int p=bfs();p!=-1;p=pre[p])
tot++;
printf("%d\n",tot-1);
return 0;
}