• 2014哈商大ICPC/ACM校赛解题报告


    被debug邀请去參加校赛,哎,被虐。。我对不起工大。。

    由于本人不搞ACM,算法处于HelloWorld水准。。

    虽然题目除了鸟不拉屎星人之外都非常水,但我能做到这个程度,全然是超水平发挥了。。

    数据:点此下载

    ==============================================================


    a:逆序数组+删除特定元素

    题目:
    小伙伴们好像非常多没接触过ICPC,那先来一道水题尝尝鲜,给出
    一个数组,和一个特征值。将这个数组中特征值值删除后逆序输出。
    EG: 数组,1 2 3 4 5 6 7特征值4
    那么输出是:
    7 6 5 3 2 1

    输入:
    输入包括3行,第一行输入N(N< 100)表示数组长度
    第二行输入 N个数
    第三行 输入特征值T

    输出:
    删除特征值后的逆序数组,每组输出要换行。

    例子输入:
    7
    1 2 3 4 5 6 7
    4
    6

    例子输出:
    765321

    代码:
    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    int main()
    {
        int n,tmp,delNum;
    
        while(cin >> n){
            vector<int> a;
            while(n--){
                cin >> tmp;
                a.push_back(tmp);
            }
            cin >> delNum;
    
            vector<int>::reverse_iterator a_rIter;
            for(a_rIter = a.rbegin();a_rIter != a.rend(); ++a_rIter){
                if(*a_rIter == delNum)
                    continue;
                cout << *a_rIter;
            }
            cout << endl;
        }
        return 0;
    }
    



    b:括号匹配


    题目:
    在公式中常常遇到大量的括号,可是这些括号匹配的对不正确呢?
    由于不同意一个括号里包括不成对的括号.
    不同类型的括号能够互相包括比方这样{()},([]),[{}], {[][]()};
    可是一种类型的括号不同意包括其它类型不成对的括号,比方这
    样就是不同意的:{(} [{] {)};
    )(,}{,][这样也是不同意的。
    如今给出一个有括号组成的字符串,推断其是否合法。

    输入:
    每组输入包括一个括号字符串

    输出:
    推断括号是字符串是否合法,合法输出yes不合法输出no
    每次输出要换行

    例子输入:
    {}{}()()(()){[()]}
    {}{}(([])){[}]


    例子输出:
    Yes
    No

    代码:
    #include <iostream>
    #include <stack>
    
    using namespace std;
    
    
    int main()
    {
        stack<char> s;
        string str;
        while(cin >> str){
            char tmp;
            bool ans = true;
            for(unsigned int i = 0 ; i < str.size();i++){
                if(str[i] == '(' || str[i] == '[' || str[i] == '{')
                    s.push(str[i]);
                else{
                    if(s.empty()){ //假设栈为空,并且还遇到这样的字符就直接No了
                        ans = false;
                        break;
                    }
                    tmp = s.top();
                    s.pop();
                    if((str[i] == ')' && tmp == '(') ||
                       (str[i] == ']' && tmp == '[') ||
                       (str[i] == '}' && tmp == '{')){
                        continue;
                    }else{
                        ans = false;
                        break;
                    }
                }
            }
            if(ans)
                cout<<"Yes"<<endl;
            else
                cout<<"No"<<endl;
        }
        return 0;
    }
    


    c: 再多一天


    题目:
    输入一个日期,你来算算第二天的日期

    输入:
    每组输入包括一个日期,格式如 2014-4-5

    输出:
    输出第二天的日期 2014-4-6;每次输出要换行;

    例子输入:
    2014-4-5
    2014-4-6

    例子输出
    2014-4-6
    2014-4-7

    代码:
    #include <iostream>
    #include <string>
    #include <vector>
    #include "stdio.h"
    
    using namespace std;
    
    class Time{
    public:
        int year;
        int month;
        int day;
    
        Time(int year,int month,int day)
        {
            this->day = day;
            this->month = month;
            this->year = year;
        }
    
        bool isRunYear(){
            if((this->year % 4 == 0 && this->year % 100 != 0) || this->year % 400 == 0)
                return true;
            return false;
        }
    
        void addOneDay(){
            this->day += 1;
    
            //do with day
            if(this->day == 32){
                this->day = 1;
                this->month += 1;
            }
            else if(this->day == 31 && (this->month == 4 || this->month == 6 || this->month == 9 || this->month == 11)){
                this->day = 1;
                this->month += 1;
            }
            else if(this->day == 30 && this->month == 2 && isRunYear()){
                this->day = 1;
                this->month += 1;
            }
            else if(this->day == 29 && this->month == 2 && !isRunYear()){
                this->day = 1;
                this->month += 1;
            }
    
            //do with month
            if(month == 13){
                this->month = 1;
                this->year += 1;
            }
        }
    
    };
    
    int main()
    {
        int y,m,d;
        while(scanf("%d-%d-%d",&y,&m,&d)==3){
            Time *t = new Time(y,m,d);
            t->addOneDay();
            cout<<t->year<<"-"<<t->month<<"-"<<t->day<<endl;
        }
        return 0;
    }
    

    /*改动于2014-4-23:9:23
    强子说,推断一个月是不是大月,直接if(this->day == 32) 就好了。。
    太有道理了,不然就冗余了。。感谢强子的修正!
    */


    一開始傻逼了,我对输入的“2014-1-1”,当成字符串,然后切割。。
    附加赠送C++分割字符串,当中vector返回的是year,month,day的int型集合体:
    vector<int> split(string str, string patternStr)
    {
        vector<int> res;
        for(unsigned int i = 0 ; i < str.size() ; i++){
            int pos = str.find(patternStr,i);
            string s;
            if(pos < str.size() && pos >= 0){
                s = str.substr(i,pos-i);
                i = pos;
            }else{
                s = str.substr(i);
            }
            stringstream ss; //string 转 int
            ss << s;
            int t;
            ss >> t;
            res.push_back(t);
        }
        return res;
    }
    


    d:相似字符串

    题目:
    如今字符串相似有个法则:假设字符串A能通过有次的变换能
    和字符串B同样那么说明他们是相似的。
    这样的变换法则是:将串头字母插入到串尾,然后总体迁移一位。
    比方:abcde cdeab
    abcde 通过将 a 置尾变成 bcdea
    bcdea 通过将 b 置尾变成 cdeab
    那么说明abcde 和 cdeab 是相似的。

    输入:
    输入包括两个等长字符串

    输出:
    若两字符串相似输出yes否则输出no

    例子输入:
    abcde cdeab
    abc acb

    例子输出:
    Yes
    No

    代码:
    #include <iostream>
    #include <string>
    
    using namespace std;
    
    
    int main()
    {
        string str1,str2;
        while(cin>>str1>>str2){
            string str3 = str2+str2;
            int length = str1.size();
    
            if(str3.find(str1)<length)
                cout<<"Yes"<<endl;
            else
                cout<<"No"<<endl;
        }
        return 0;
    }
    

    在str2+str2中怎样能找到str1,就是相似。。
    string.find() 找不到后会返回一个非常大的值。。不是-1。。

     
    /*改动于2014-4-28
    C++的find()找不到的时候究竟返回什么,有的说是-1,有的说是无穷大。
    str.find("e")返回值是string::size_type。由于 string::size_type (由字符串配置器 allocator 定义) 描写叙述的是 size,故需为无符号整数型别。
    由于缺省配置器以型别 size_t 作为 size_type,于是 -1 被转换为无符号整数型别。
    找不时,返回值是string::npos。 
    npos是这样定义的: static const size_type npos = -1;
    但输出是做无符号整数型别输出,即-1的补码4294967295。

    所以应该这么用:
    当 str.find("哦")==string::npos时则说明字符串str中不存在“哦”这个字符,
    反之,str.find("哦")!=string::npos则说明字符串str中存在“哦”这个字符

    用string:npos来推断就可以。
    */

    e:迷宫


    题目:
    小伙伴们钻进迷宫寻找宝藏,你是否能从(左边)入口開始进去,寻找到
    宝物呢。

    输入:
    给出一个迷宫矩阵图,0表示通过,1表示墙壁。有左上角进入迷
    宫開始寻宝。

    输出:
    输出寻找到的宝物符号,每次输出要换行

    Sample In:
    1111111111111111111111
    0000000000000000000001
    1111111111111111111101
    1111111111111111111101
    11000000000000*1111101
    1111111111111111111101
    1111111111111111111101
    1+11111111111111111101
    1000000000000000000001
    1111111111111111111111

    Sample Out:
    +


    代码:
    #include <iostream>
    #include "stdio.h"
    
    using namespace std;
    
    char m[100][100];
    
    int r = 0; //row
    int c = 0; //column
    
    void dfs(int x,int y)
    {
        if(m[x][y] != '0')
            cout<<m[x][y]<<endl;
        m[x][y] = '1';//标记訪问过
        //down
        if(x+1 < r && m[x+1][y] != '1'){
            dfs(x+1,y);
        }
        //up
        if(x-1 >= 0 && m[x-1][y] != '1'){
            dfs(x-1,y);
        }
        //right
        if(y+1 < c && m[x][y+1] != '1'){
            dfs(x,y+1);
        }
        //left
        if(y-1 >= 0 && m[x][y-1] != '1'){
            dfs(x,y-1);
        }
    
    }
    
    int main()
    {
        //freopen("in.txt","r",stdin);
        //freopen("out.txt","w",stdout);
    
        string t;
        int index = 0 ;
        while(cin>>t){
            for(unsigned int i=0;i<t.size();i++)
                m[index][i] = t[i];
            c = t.size();
            index ++;
        }
        r = index;
    
        //入口在左边,找入口
        for(int i = 0;i<r;i++){
            if(m[i][0] == '0')
                dfs(i,0);
        }
    
    
        return 0;
    }
    



    f:小胖子厨师


    题目:
    大家都知道小胖子是个吃货,可是都不知道小胖子还是个非常厉害
    的厨师,他的拿手功夫是切墩><.
    有一天他切肉时陷入了沉思:我怎么才干用最少的刀数把肉切的
    更碎呢(咱们先不考虑3维问题,仅仅在平面上思考吧) 。
    比方,我一刀下去能切成两块,两刀下去能切成四块,小胖子一
    气之下切了N多刀,肉最多被切成了多少块(预计不能吃了) ?

    In:
    输入小胖子切了多少刀N

    Out:
    输出肉最多能被切成多少块,每次输出要换行

    Sample in:
    1
    2

    Sample out:
    2
    4

    代码: 
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        int n;
        while(cin>>n){
            int ans = (1+n)*n/2 + 1;
            cout<<ans<<endl;
        }
        return 0;
    }
    

    这道题不得不停下来吐槽下,平面切割问题。。。

    当有n-1条直线时,平面最多被分成了f(n-1)个区域。

    则第n条直线要是切成的区域数最多,就必须与每条直线相交且不能有同一交点。

    这样就会得到n-1个交点。

    这些交点将第n条直线分为2条射线和n-2条线断。

    而每条射线和线断将以有的区域一分为二。

    这样就多出了2+(n-2)个区域。

    故:
    f(n)=f(n-1)+n
          =f(n-2)+(n-1)+n
           ……
          =f(1)+1+2+……+n
          =n(n+1)/2+1

    g:小气的自来水公司


    题目:
    如今有N个村庄,村庄与村庄之间有自来水管联通,如今自来水公
    司为了节省耗材将拆除多余耗材, 为了使拆卸得到的耗材最多而且要
    保证村庄之间水路想通。

    输入:
    首先输入m n, (m,n< 26)m表示有m个村庄,n表示村庄之间有多
    少水路。
    接下来有n行,每行包括 两个大写字符,和一个整形数
    Eg.AB 10,表示村庄A B之间存在水路且长度是10

    输出:
    拆卸结束后,村庄之间水路的总长度。

    Sample in:
    3 2
    AB 1
    B C 1

    Sample out:
    2

    代码:
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <vector>
    #include "stdio.h"
    
    using namespace std;
    
    #define MAXN 1000
    #define INF 1<<30
    
    int closest[MAXN],lowcost[MAXN],m;// m为节点的个数
    int G[MAXN][MAXN];//邻接矩阵
    
    int prim(int m)
    {
        for(int i=0;i<m;i++)
        {
            lowcost[i]=INF;
        }
        for(int i=0;i<m;i++)
        {
            closest[i]=0;
        }
    
    
        closest[0]=-1;//增加第一个点,-1表示该点在集合U中,否则在集合V中
        int num=0,ans=0,e=0;//e为最新增加集合的点
        while(num<m-1)//增加m-1条边
        {
            int micost=INF,miedge=-1;
            bool flag = false;
            for(int i=0;i<m;i++){ //找出最小边
                if(closest[i]!=-1)
                {
                    int temp=G[e][i];
                    if(temp<lowcost[i])
                    {
                        lowcost[i]=temp;
                        closest[i]=e;
                    }
                    if(lowcost[i]<micost){
                        micost=lowcost[i];
                        miedge = i;
                        flag = true;
                    }
                }
            }
            if(!flag){
                return -1;
            }
            ans+=micost;
            closest[miedge]=-1;
            e = miedge;
            num++;
        }
    
        return ans;
    }
    
    int main()
    {
        int m,n;
        while(scanf("%d %d",&m,&n) == 2){
            for(int i=0;i<m;i++) //清空数组
                for(int j=0;j<m;j++)
                    G[i][j] = INF;
    
            char a,b;
            int w;
            for(int i = 0 ; i < n;i++){
                cin>>a>>b>>w;
                G[a-'A'][b-'A'] = w;
                G[b-'A'][a-'A'] = w;
            }
    
            int ans = prim(m);
            if(ans == -1)
                cout<<"Can't do it"<<endl;
            else
                cout<<"Total:"<<ans<<endl;
        }
        return 0;
    }
    




    h:吐槽星人大战鸟不拉屎大王


    题目:
    HUC要举办ACM/ICPC校赛的消息已经传遍了整个宇宙,位于
    M77星云的鸟不拉屎大王为了赢得这次比赛, 他决定派出自己最为自
    傲的队伍。
    而在宇宙的深处,宇宙间的和平使者,总是破坏鸟不拉屎大王毁
    灭宇宙大阴谋,继呕吐曼之后成为全宇宙大英雄的吐槽星人,在得知
    了这个消息之后,为了阻止鸟不拉屎大王,也决定选出对应的队伍去
    參加比赛。 (他们总是这样,不管鸟不拉屎大王在做什么,阻止已经
    成为了习惯)可是宇宙间总是充斥着各种邪恶的存在,吐槽星人当然
    不可能将所有的力量放在鸟不拉屎大王身上 (比方说位于古老地球的
    蛇精,女王大人,在俘获了福禄小金刚之后也开展了妄图统治宇宙的
    邪恶计划)所以吐槽星人在得知了鸟不拉屎大王派出的队伍之后, 也
    派出了队伍。
    在出发比赛的当天,因为星际虫洞发生了严重的交通事故,造成
    了交通大堵塞。鸟不拉屎大王的队伍就和他们宿世的仇敌,吐槽星人
    的队伍坐在了同一辆星际飞船上開始了旅行 (不要问我他们为什么没
    有自己的旅行飞船, 要知道就算鸟不拉屎大王这样的宇宙高富帅的存在
    也会与资金紧张的时候,恰恰吐槽星人也受到了相同的困扰) 。我们
    知道每一个吐槽星人都有自己生而拥有的吐槽之力, 而鸟不拉屎大王的
    手下也有属于自己的翔之力 (能力的数值都在1 ~ n ^ 2之间的整数) 。
    如今正在飞往比赛地点的路程上发现了翔之力的秘密。 (这个是个大
    消息)他们决定展开自己的秘密计划,详细的内容就是当时在飞船之
    中,鸟不拉屎大王的手下坐成一排编号为0~p,吐槽星人坐一排编
    号为0~q,两排平行,吐槽星人在位置不变的情况下同一时候发动吐槽
    之力,各自能力会形成各自的一道能量波,能量波不能互相交叉, 发
    向对面的鸟不拉屎大王的手下, 这样就能够将对方成功吸收成为自己
    的人,为比赛加大胜利的筹码。我们会给出两方相应的翔之力和吐槽
    之力,你要计算出能够吸收的最大人数,当然因为基因的不同,每一个
    人的能力不可能呈现出同样的大小。 而可以成功计算出最大吸收人数
    的会有幸成为幸得吐槽星人, 维护宇宙的和平, 真是个有意义的工作。
    比方这两支队伍的能力各自是
    1 7 5 4 8 3 9
    1 4 3 5 6 2 8 9
    我们能够选择1 -> 4 ->8 -> 9 或者 1 -> 5 -> 8 -> 9 或者 1 -> 4 -> 3
    -> 9 这三种吸收模式
    而1->5->3->9这样的模式就不能够

    INPUT:
    输入的第一行为数据组数Case (Case <= 10),接下来每组数据包括3
    行,第一行为3个整数n,p,q ( 2 <= n <= 250, 0 <= q, p <= n ^ 2 ),
    接下来第二行是鸟不拉屎大王的手下的能量值,都是1 ~ n^2之间的
    整数,第三行是吐槽星人,格式同上。

    OUTPUT:
    对于每组数据,输出“Case x: y” ,x从1開始一直到Case,而y表示
    吸收的最大人数。

    sample input:
    2
    3 6 7
    1 7 5 4 8 3 9
    1 4 3 5 6 2 8 9
    4 15 5
    10 16 3 0 1 8 14 15 13 6 9 5 7 12 11 2
    5 15 11 7 2 0

    sample output:
    Case 1: 4
    Case 2: 3

    /*改动于2014-4-28

    这道题用到了:偏序集的Dilworth定理!

    样例例如以下:

    求一个序列的最长上升子序列。其最大值即等于不上升子序列的最小划分数。
    这就涉及到组合数学中偏序集的 Dilworth定理,代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using namespace std;
    
    int a[100],f[100],g[100];
    
    int main(){
        freopen("lmis.in","r",stdin);
        freopen("lmis.out","w",stdout);
        int n,i;
        scanf("%d",&n);
        memset(g,0x7f,sizeof(g));
        memset(f,0,sizeof(f));
        for(i=0;i<n;i++)
          scanf("%d",&a[i++]);
    
        for(i=0;i<n;i++){
                int k=lower_bound(g+1,g+n,a[i])-g;
                f[i]=k+1;
                g[k+1]=a[i];
        }
    
        printf("%d
    ",*max_element(f,f+n));
        return 0;
    }


    */


    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int MAXN=250*250+10;
    const int INF=9999999;
    int b[MAXN],n,p,q;
    int g[MAXN],id[MAXN],x[MAXN];//g[i]:ICS为i时候的最小下标,x[i]:lis值
    int main()
    {
        //freopen("1.txt","r",stdin);
        int T,kase=1;
        while(scanf("%d",&T)==1){
            kase=1;
            while(T--)
            {
                int temp,len=0;
    
                scanf("%d%d%d",&n,&p,&q);
                memset(id,0,sizeof(id));
                for(int i=1;i<=p+1;i++)
                {
                    scanf("%d",&temp);
                    id[temp]=i;
                }
                for(int i=0;i<q+1;i++)
                {
                    scanf("%d",&temp);
                    if(id[temp])
                        b[len++]=id[temp];
                }
    
                for(int i=0;i<=len;i++)
                    g[i]=INF;
                    
                int ans=0;
                for(int i=0;i<len;i++)
                {
                    int k=lower_bound(g+1,g+len+1,b[i])-g;
                    x[i]=k;
                    g[k]=b[i];
                    ans=max(ans,x[i]);
                }
                printf("Case %d: %d
    ",kase++,ans);
    
            }
        }
        return 0;
    }
    



  • 相关阅读:
    MD文件利用标题等级进行分割代码实现
    IDEA插件-Git Commit Template
    IDEA插件-Translation
    IDEA使用-Debug回到上一步
    Java语法糖详解
    MySQL 事务的隔离级别初窥
    Java异常体系概述
    ssh-copy-id三步实现SSH免密登录
    深入理解ThreadLocal
    使用Guava RateLimiter限流入门到深入
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/4004762.html
Copyright © 2020-2023  润新知