1.变位词问题(18分)
问题描述
所谓变位词,是指组成各个单词的字母完全相同,只是字母排列的顺序不同。例如:silent和listen就是一对变位词。给出两个字符串,要求判断其是否互为变位词,若是,返
回“Yes”,否则返回“No”。
Input
输入正整数N,表示N例测试。接着输入N组数据,每组数据一行,包含两个字符串。
Output
对每组输入数据,输出一行,“Yes”表示是变位词,“No”表示不是变位词。
Sample Input
2
silent listen
stop sort
Sample Output
Yes
No
解题思路:
利用map把两个字符串里的每个字符的个数统计到数组a和数组b中。如果完全相同,返回Yes,不同的话返回No。
PS:可能两个字符串中会包含!@#$%^&等字符。
代码:
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<cstring>
#include<map>
#define maxn 1005
using namespace std;
int a[1005];
int b[1005];
char str1[10005];
char str2[10005];
map <char,int> mq;
int main()
{
int n,i,len;
while(cin>>n)
{
while(n--)
{
int t=0;
mq.clear();
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
cin>>str1;
len=strlen(str1);
for(i=0; i<len; i++)
{
if(!mq[str1[i]])
{
mq[str1[i]]=++t;
a[t]++;
}
else
{
a[mq[str1[i]]]++;
}
}
cin>>str2;
len=strlen(str2);
for(i=0; i<len; i++)
{
if(!mq[str2[i]])
{
mq[str2[i]]=++t;
b[t]++;
}
else
{
b[mq[str2[i]]]++;
}
}
/*if(strcmp(str1,str2)==0)
{
cout<<"No"<<endl;
continue;
}*/
int flag=1;
for(i=0; i<1000; i++)
{
if(a[i]!=b[i])
{
flag=0;
break;
}
}
if(flag) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
}
return 0;
}
/*
4
beijinguniversityofpostsandtelecommunications
nnsemnoimfeiaugtyittouinjpdonssaiebcsiervctol
schoolofcomputerscience icooeeorhufmpcntepcslcs
cdmpnb.enuet.@ua name@bupt.edu.cn
congratulations nncatrlsaoogucit
*/
2.加密问题(16分)
问题描述
信息社会,密码与我们生活息息相关。为了安全起见,可通过简单加密机制把明文加密成密文。这里的加密机制是利用手机上的字母与数字键的对应关系:1--1,abc--2,def--3,ghi--4,jkl--5,mno--6,pqrs--7,tuv--8,wxyz--9,0--0。加密机制为:
1)密码中出现的小写字母都变成对应的数字;
2)密码中出现的大写字母都变成小写之后往后移一位,如果是大写字母Z,则后移一位变成a;
3)数字和其他的符号都不做变换。
声明:密码中没有空格,可包含特殊字符,如~!@#$等。
Input
输入正整数N,表示N例测试。接着输入N组数据,每组数据一行,包含一个明文字符串,长度不超过100。
Output
对每组输入数据,输出一行对应的密文。
Sample Input
2
ZHANGsan&2016
Name@32#
Sample Output
Aiboh726&2016
O263@32#
代码:
PS:代码写的比较乱,用了很多if,else。。。
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<cstring>
#define maxn 1005
using namespace std;
char str1[1005];
int main()
{
int n,i,len;
while(cin>>n)
{
while(n--)
{
cin>>str1;
len=strlen(str1);
for(i=0; i<len; i++)
{
if(str1[i]>='A'&&str1[i]<='Y')
{
str1[i]=str1[i]-'A'+'a'+1;
}
else if(str1[i]=='Z')
{
str1[i]='a';
}
else if(str1[i]>='a'&&str1[i]<='c')
{
str1[i]='2';
}
else if(str1[i]>='d'&&str1[i]<='f')
{
str1[i]='3';
}
else if(str1[i]>='g'&&str1[i]<='i')
{
str1[i]='4';
}
else if(str1[i]>='j'&&str1[i]<='l')
{
str1[i]='5';
}
else if(str1[i]>='m'&&str1[i]<='o')
{
str1[i]='6';
}
else if(str1[i]>='p'&&str1[i]<='s')
{
str1[i]='7';
}
else if(str1[i]>='t'&&str1[i]<='v')
{
str1[i]='8';
}
else if(str1[i]>='w'&&str1[i]<='z')
{
str1[i]='9';
}
}
cout<<str1<<endl;
}
}
return 0;
}
/*
2
School!Of@Computer#Science$NLP2016^
BYR*bupt%BeiJing/China
*/
3.求连续子数组最大和(20分)
问题描述
输入一个整形数组,数组里有正数也有负数。数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。求所有子数组的和的最大值,并给出子数组的首末位置。
Input
输入正整数N,表示N例测试。接着输入N组数据,每组数据一行,包含一个数组。
Output
对每组输入数据,输出该数组对应的最大连续子数组和,子数组的首位置,末位置。
Sample Input
2
1 -2 3 10 -4 7 2 -5
1 -9 5 5
Sample Output
18 2 6
10 2 3
解题思路:
如果用a表示给定的初始数组,dp[i]表示以i为末位置的最大连续子数组的和,那么dp[i]=max(dp[i-1]+a[i],dp[i])
代码:
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<cstring>
#define maxn 1005
using namespace std;
int a[1005];
int dp[1005];
char str[1005];
int ma(int a,int b)
{
if(a>b) return a;
return b;
}
int main()
{
int n,i,len,m;
while(cin>>n)
{
gets(str);
while(n--)
{
memset(dp,0,sizeof(dp));
m=0;
gets(str);
len=strlen(str);
int tmp=0,flag=0;
for(i=0; i<len; i++) //将字符串处理成int数组保存在数组a中
{
if(str[i]=='-')
{
flag=1;
}
else if(str[i]==' ')
{
if(flag)
a[m++]=0-tmp;
else
a[m++]=tmp;
flag=0;
tmp=0;
}
else
tmp=tmp*10+(str[i]-'0');
}
if(flag)
a[m++]=0-tmp;
else
a[m++]=tmp;
flag=0;
tmp=0;
/*
cout<<m<<endl;
for(i=0;i<m;i++)
cout<<a[i]<<" ";
cout<<endl;
*/
if(a[0]>=0) dp[0]=a[0];
else dp[0]=0;
for(i=1; i<m; i++) //利用递推公式
dp[i]=ma(a[i],dp[i-1]+a[i]);
int fla=0; //处理没有正数的情况 ,特判
for(i=0; i<m; i++)
{
if(a[i]>0)
{
fla=1;
}
}
if(fla==0) //处理没有正数的情况 ,特判
{
int ss,ee,mm=-1000000000;
for(i=0; i<m; i++)
{
if(a[i]>mm)
{
mm=i;
ss=i;
ee=i;
}
}
cout<<mm<<" "<<ss<<" "<<ee<<endl;
continue;
}
int mm=-1000000000,e,s;
for(i=0; i<m; i++) //找到dp的最大值
{
if(dp[i]>mm)
{
mm=dp[i];
e=i;
}
}
int pp=mm;
for(i=e; i>=0; i--) //根据总和和末位置找到起始位置
{
pp-=a[i];
if(pp==0)
{
s=i;
break;
}
}
cout<<mm<<" "<<s<<" "<<e<<endl;
}
}
return 0;
}
/*
100
1 -2 3 10 -4 7 2 -5
1 -9 5 5
-1 -1 -1
-1 2 2
0 -1 -1
3
1 -2 3 10 -4 7 2 -5 -19 10 8 -3 -8 3
61 59 62 -107 22 23 -113 14 54 57 -76 -116 78 0 7 -70 50 -58 -94 1 53 38 55 65 16 48 32 8 27 8 -108 63 -50 14 69 -103 -112 -51 40 53
96 30 163 37 65 -232 121 -295 15 119 11 177 -149 128 68 -217 -290 196 169 -32 -261 194 -85 48 -87 84 89 -152 -98 96 177 198 -144 154 -67 125 -224 -110 182 -155 72 43 92 -127 40 84 85 -285 171 69 157 176 -24 149 -98 59 188 58 193 145 -208 32 -9 182 -191 97 54 92 101 -79 -111 35 -28 -48 96 128 46 -193 -182 -111 45 170 182 136 147 79 12 53 11 -171 90 199 26 120 60 59 52 -111 -113 148
*/
4.整数的最小平方分解(23分)
问题描述
给定一个正整数n,总能分解成若干个完全平方数的和(这里完全平方数为1,4,9,16,25,...),请找出n的最小平方分解数,例如,n=12时,12=4+4+4,返回最小平方分解数3;n=13时,13=4+9,返回最小平方分解数2。
Input
输入正整数N,表示N例测试。接着输入N组数据,每组数据一行,包含一个正整数。
Output
对每组输入数据,输出其最小平方分解数。
Sample Input
4
12
13
2016
Sample Output
2
3
2
3
解题思路:
思路一,可以利用递归的思想dfs(cur,deep),寻找最优解。cur是当前的值,deep是当已经用的平方数的个数。 如果cur为0,那么把deep和结果比较,选小的。为了记忆化搜索,用vis数组保存cur的是否访问过,还有p数组,p[i]到达cur状态所用的最小步数。
1)如果cur没访问过,便访问。
2)如果cur访问过,并且当前到达的步数更少的话,也可以继续搜索。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define INF 0x7fffffff
#define maxn 1000005
using namespace std;
int ans;
int a[maxn];
int m,n;
int vis[maxn];
int p[maxn];
void dfs(int cur,int deep)
{
if(deep>10)
return;
if(cur==0)
{
if(deep<ans)
{
ans=deep;
return;
}
}
else if(cur<0)
{
return;
}
for(int i=sqrt(cur); i>=1; i--)
{
int t=cur/(i*i);
for(int j=1; j<=t; j++)
{
if(!vis[cur-j*i*i])
{
vis[cur-j*i*i]=1;
p[cur-j*i*i]=deep+j;
dfs(cur-j*i*i,deep+j);
}
if(vis[cur-j*i*i]&&p[cur-j*i*i]>deep+j)
{
vis[cur-j*i*i]=1;
p[cur-j*i*i]=deep+j;
dfs(cur-j*i*i,deep+j);
}
}
}
}
int main()
{
while(cin>>n)
{
while(n--)
{
memset(vis,0,sizeof(vis));
memset(p,0,sizeof(p));
cin>>m;
ans=INF;
dfs(m,0);
cout<<ans<<endl;
}
}
return 0;
}
思路二,这个题是典型的完全背包。
具体可以参加背包九讲问题。
当然这个题有些许不同,动态转移方程为dp[j]=min(dp[j-i*i]+1,dp[j]);
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define INF 0x7fffffff
#define maxn 400005
using namespace std;
int dp[maxn];
void pre()
{
int i,j;
for(i=1;i<maxn;i++)
dp[i]=INF;
dp[0]=0;
for(i=1;i<=1000;i++)
{
for(j=0;j<maxn;j++)
{
if(j>=i*i&&dp[j-i*i]!=INF)
{
dp[j]=min(dp[j-i*i]+1,dp[j]);
}
}
}
}
int main()
{
pre();
int n,m;
while(cin>>n)
{
while(n--)
{
cin>>m;
cout<<dp[m]<<endl;
}
}
return 0;
}
5.矩阵的ZigZag排列(23分)
问题描述
输入一个仅包含正整数n×n矩阵array,输出该矩阵的ZigZag排列,其中array[0][0]是排列的起点,array[n-1][n-1]是排列的终点。例如:输入一个4×4的矩阵
输出其ZigZag排列:1 2 5 9 6 3 4 7 10 13 14 11 8 12 15 16
Input
输入正整数N,表示N例测试。接着输入N组数据,每组数据为一个n×n的矩阵,即先输入n,然后输入n行数据。
Output
对每组输入数据,输出一行该矩阵的ZigZag排列。
Sample Input
2
2
1 2
3 4
4
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
Sample Output
1 2 3 4
1 2 5 9 6 3 7 10 13 14 11 8 12 15 16
解题思路:
其实这个题目只有四个方向,正右,左下,正下,右上。如果x,y表示当前坐标。这四个方向坐标变化依次为+{{0,1},{1,-1},{1,0},{-1,1}};
可以采用递归的思想,关键就是判断方向,什么时候改变方向,有几种可能。
代码:
#include<iostream>
#include<cstdio>
#define maxn 1005
using namespace std;
int a[maxn][maxn];
int d[4][2]= {{0,1},{1,-1},{1,0},{-1,1}};
int m;
void dfs(int curx,int cury,int dir)
{
cout<<a[curx][cury]<<" ";
if(curx==m&&cury==m)
return;
curx=curx+d[dir][0];
cury=cury+d[dir][1];
if(dir==0)
{
if(curx==1)
dir=1;
else
dir=3;
}
else if(dir==1)
{
if(curx==m)
dir=0;
else if(cury==1)
dir=2;
else
dir=1;
}
else if(dir==2)
{
if(cury==1)
dir=3;
else
dir=1;
}
else
{
if(curx==1)
dir=0;
else if(cury==m)
dir=2;
else
dir=3;
}
dfs(curx,cury,dir);
}
int main()
{
int n,i,j;
while(cin>>n)
{
while(n--)
{
cin>>m;
for(i=1; i<=m; i++)
{
for(j=1; j<=m; j++)
{
cin>>a[i][j];
}
}
//cout<<"****"<<endl;
dfs(1,1,0);
cout<<endl;
}
}
return 0;
}
/*
2
8
26 -57 30 16 0 45 -16 -32
-47 -53 18 0 38 -28 12 21
2 -49 9 41 53 -59 -7 -14
51 21 1 27 38 -29 29 37
60 26 36 -44 14 -12 -58 57
1 -2 23 32 30 -16 62 10
-44 17 34 23 14 -36 46 36
26 -3 0 40 7 -5 49 51
16
-226 247 6 -116 227 32 234 -42 -125 -36 153 71 -144 110 -66 -217
-3 80 -65 6 -137 130 27 -124 244 -241 -28 197 -170 97 2 30
45 -150 69 110 100 165 54 217 72 196 207 219 -72 159 93 107
225 159 252 62 50 99 13 -92 236 14 -125 229 127 202 11 176
219 -148 -7 163 90 -157 -98 83 -172 119 208 -183 151 149 230 207
-17 79 -12 168 165 -108 130 -230 136 79 232 -200 191 180 111 36
84 30 -5 252 -132 13 221 58 74 124 180 -90 76 150 -23 -237
25 -147 120 108 -220 52 77 148 -216 14 45 35 110 173 188 185
123 -50 112 167 52 -131 -29 10 -221 72 -220 -207 -73 9 -22 177
-249 75 83 -79 202 27 -146 -3 195 126 163 210 75 159 31 -250
-87 -43 105 -107 142 -219 207 -196 230 -225 -80 -79 -198 32 216 101
59 63 155 -14 -33 -194 -88 156 86 104 146 163 157 14 108 -43
184 231 166 224 81 126 205 159 241 -181 -224 -6 248 -1 170 115
120 76 98 -58 -243 152 107 86 62 -215 43 165 27 -105 -81 165
34 -248 125 115 2 226 21 -43 163 168 99 211 -1 -246 215 204
-208 199 19 -120 15 146 -29 -13 166 89 148 -250 -66 104 40 -253
*/