北理工2019年计算机学科夏令营上机考试

第一题:类似LeetCode上括号匹配,输入的字符串包括三种字符,分别是"["  "]"   "*",其中“*”可以替换为“[”、"]"或者就是它本身,要求括号能配对即可,如果能匹配,输出匹配后的结果,否则输出false。

输入:*[[***

输出:*[[]]*

输入:*[[]

输出:false

注意:输出格式的隐含要求是尽量不改变原有的*。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<stack>
using namespace std;

int main()
{
    char s[55];
    char ans[55];
    cin>>s;
    memcpy(ans,s,sizeof(s));
    int l = strlen(s);
    stack<int> pq;//预处理,先把现有的[]匹配掉,这样就只剩下[或]了。
    for(int i=0;i<l;i++)
    {
        if(s[i]=='[')pq.push(i);
        else if(s[i]==']'&&!pq.empty())
        {
            int x = pq.top();
            s[x]='0';
            s[i]='0';
            pq.pop();
        }
    }
    stack<int> q;//之后就处理[或者]就好了
    for(int i=0;i<l;i++)
    {
        if (s[i] == '[')q.push(i);
        if (s[i] == '*')
        {
            if (q.empty()) q.push(i);//星号进去的答案就不改
            else
            {
                int x = q.top();
                q.pop();
                if (s[x] == '[')//如果是星号匹配星号两个都不改
                {
                    ans[i] = ']';
                }
            }
        }
        if (s[i] == ']')
        {
            if (q.empty())
            {
                cout << "false" << endl;
                return 0;
            }
            else 
            {
                int x = q.top();
                q.pop();
                ans[x] = '[';
            }
        }
    } 
    while (!q.empty())
    {
        int x = q.top();
        q.pop();
        if(s[x]=='[')
        {
            cout<<"false"<<endl;
            return 0;
        }
    }
    cout<<ans<<endl;
    return 0;
}

第一次做:没有考虑[*]等奇数个*的情况,解决方案是预处理,把能匹配的先匹配了(如上)。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<stack>
using namespace std;

int main()
{
    char s[50];
    char ans[50];//最后的输出结果
    cin >> s;
    memcpy(ans, s, sizeof(s));
    int l = strlen(s);
    stack<int>q;
    for (int i = 0; i < l; i++)
    {
        if (s[i] == '[')q.push(i);
        if (s[i] == '*')
        {
            if (q.empty()) q.push(i);//星号进去的答案就不改
            else
            {
                int x = q.top();
                q.pop();
                if (s[x] != '*')//如果是星号匹配星号两个都不改
                {
                    ans[x] = '[';
                    ans[i] = ']';
                }
            }
        }
        if (s[i] == ']')
        {
            if (q.empty())
            {
                cout << "false" << endl;
                return 0;
            }
            else q.pop();
        }
    }
    if (!q.empty()) cout << "false" << endl;
    else
    {
        for (int i = 0; i < l; i++)cout << ans[i];
        cout << endl;
    }
    return 0;
}
View Code

刘先生解题方案(很稳妥!):

#include <iostream>
#include <string>
#include <stack>
using namespace std;

struct e{//记录不匹配的括号信息和其下标; 
    int i;
    char c;
};

int main(){
    string s;
    cin>>s;
    stack<e> sta;//结构体栈; 
    for(int i=0;i<s.length();i++){//遍历输入的字符串,遇到 [入栈,遇到 ]判断是否可以弹出栈顶,若不能也入栈; 
        if(s[i]=='['){
            e temp;
            temp.i=i;
            temp.c='[';
            sta.push(temp);
        }
        if(s[i]==']'){
            if(!sta.empty()){//栈不空且栈顶结构体的信息为 [才能弹出,其他情况入栈; 
                e temp=sta.top();
                if(temp.c=='[') {
                    sta.pop();
                }
                else{
                    e temp;
                    temp.i=i;temp.c=']';
                    sta.push(temp);
                }
            }
            else{
                e temp;
                temp.i=i;temp.c=']';
                sta.push(temp);
            }
        }
    }
    if(sta.empty()) {//若遍历完后栈空,则说明本身匹配,输出,返回,程序结束; 
        cout<<s<<endl;
        return 0;
    }
    else{//若不空则说明有不匹配的元素存在,一一判断是否可以修改为匹配; 
        while(!sta.empty()){
            bool change=false;//默认当前操作元素无法更改正确; 
            e temp=sta.top();//取出栈顶一个不匹配的括号; 
            sta.pop();
            if(temp.c=='['){//若为左括号,在原字符串右边找最近的一个*改为右括号,找不到则无法改正,输出false,返回; 
                for(int i=temp.i+1;i<s.length();i++){
                    if(s[i]=='*') {
                        s[i]=']'; 
                        change=true;
                        break;
                    }
                }
                if(!change){
                    cout<<"false"<<endl; return 0;
                }
            }
            if(temp.c==']'){//若为 ],同理,在原字符串左侧寻找*改为左括号,找不到输出false,返回; 
                for(int i=temp.i-1;i>=0;i--){
                    if(s[i]=='*') {
                        s[i]='[';
                        change=true;
                        break;
                    }
                }
                if(!change){
                    cout<<"false"<<endl; return 0;
                }
            }
        }
    }
    cout<<s;//若程序正常进行到这里说明经修改后可实现括号匹配,输出更正后字符串即可; 
    return 0;
}
View Code

第二题:输入m个数(0<m<50),从中选取不相邻的任意多个数,求最大和。

解题思路:一维动规,思路比较清晰。

每次都考虑后一位选或者不选。以6 3 7 9 -1 -1 6为例。

  • 状态a[i]为第i位及之前所求的的最大和。
  • 状态转移方程:a[i]=max(a[i-1],s[i]+a[i-2])

每次状态更新的时候都要看第i位的数字是否要选,那就需要去衡量s[i]+a[i-2]是否比a[i-1]更大。因为选择第i位就一定不会选择i-1位。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;


int main()
{
    int s[55];
    int a[55];//动规数组
    int m;
    bool allneg = true;
    cin >> m;
    for (int i = 0; i < m; i++)
    {
        cin >> s[i];
        if (s[i] >= 0)allneg = false;
    }
    if (m == 1) //只有一个数
    {
        cout << s[0] << endl; return 0 ;
    }
    if (allneg)//全是负数,则输出最大的负数
    {
        int maxneg = s[0];
        for (int i = 1; i < m; i++)
        {
            maxneg = max(maxneg, s[i]);
        }
        cout << maxneg << endl;
    }
    else//至少有一个非负数,一维动规,一步步往前拱
    {
        a[0] = max(s[0], 0);
        a[1] = max(s[1], a[0]);
        for (int i = 2; i < m; i++)
        {
            a[i] = max(a[i - 1], a[i - 2] + s[i]);
        }
        cout << a[m - 1] << endl;
    }
    system("pause");
    return 0;
}

 

posted @ 2019-08-31 11:23  郭怡柔  阅读(308)  评论(0)    收藏  举报