帝国国王科技大学上机题解

1.变位词问题(18分)

 

问题描述

所谓变位词,是指组成各个单词的字母完全相同,只是字母排列的顺序不同。例如:silentlisten就是一对变位词。给出两个字符串,要求判断其是否互为变位词,若是,返

回“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--1abc--2def--3ghi--4jkl--5mno--6pqrs--7tuv--8wxyz--90--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,总能分解成若干个完全平方数的和(这里完全平方数为1491625...),请找出n的最小平方分解数,例如,n=12时,12=4+4+4,返回最小平方分解数3n=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
*/



评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值