算法入门竞赛 第五章例题 题解

5-1 Where is the Marble? uva10474
题意:在一排数中查询某个数的位置。
思路:运用STL算法库sort,lower_bound().(查找大于等于x的第一个位置),

#include<bits/stdc++.h>
using namespace std;
const int maxn=10100;
int a[maxn];
int main()
{
    int n,q,t=0;
    while(cin>>n>>q)
    {
        if(!n&&!q) break;
        cout<<"CASE# "<<++t<<":"<<endl;
        for(int i=0;i<n;i++) cin>>a[i];
        sort(a,a+n);
        while(q--)
        {
          int x;cin>>x;
          int pos=lower_bound(a,a+n,x)-a;
          if(a[pos]==x) cout<<x<<" found at "<<pos+1<<endl;
          else cout<<x<<" not found"<<endl;
        }
    }
}

5-2 The Blocks Problem uva101
题意:从左到右,有1~n个木块,模拟四种操作。
move a onto b;move a over b;pile a onto b;pile a over b;
思路:由于每个数组长度变化,不定长,正好运用vector.
找出四种操作的共性与差异 ,move 与pile差别就是,要不要把a所在堆上方木块归位。onto 与 over 差别是要不要把 b上面的归位。
这样,总结 这四种操作,我们只用写三个函数,find(int a,int &p,int &h)找到a所在堆的位置,以及他在这个堆高度。clear_above(int p,int h)将p堆h高度以上的木块归位。pile_onto(int p,int h,int p2)将p堆h高度以上木块落在p2堆上。

#include<cstring>
#include<cstdio>
#include<vector>
#include<iostream>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int N=30;
int inf=0x3f3f3f3f;
LL mod=1e9+7;
vector<int>pile[N];
int n;
void find_block(int a,int &p,int &h)
{
    for(p=0;p<n;p++)
     for(h=0;h<pile[p].size();h++)
       if(a==pile[p][h]) return;
}

void clear_above(int p,int h)
{
    for(int i=h+1;i<pile[p].size();i++)
        pile[pile[p][i]].push_back(pile[p][i]);
    pile[p].resize(h+1);
}

void pile_onto(int pa,int ha,int pb)
{
    for(int i=ha;i<pile[pa].size();i++)
     pile[pb].push_back(pile[pa][i]);
     pile[pa].resize(ha);
}

void print()
{
    for(int i=0;i<n;i++)
    {
      printf("%d:",i);
      for(int j=0;j<pile[i].size();j++)
        printf(" %d",pile[i][j]);
      printf("\n");
    }
}

int main()
{
    while(~scanf("%d",&n))
    {
        int a,b;
        string s1,s2;
        for(int i=0;i<n;i++) pile[i].push_back(i);
        while(cin>>s1)
        {
            //cout<<s1<<endl;
            if(s1=="quit") break;
            cin>>a>>s2>>b;
            int pa,pb,ha,hb;
            find_block(a,pa,ha);
            find_block(b,pb,hb);
            if(pa==pb) continue;
            if(s1=="move") clear_above(pa,ha);
            if(s2=="onto") clear_above(pb,hb);
            pile_onto(pa,ha,pb);
        }
        cout<<"ok"<<endl;
        print();
    }
}

5-3 Andy’s First Dictionary uva10815
题意:输入一段字符串,让你找出所有不重复的单词,不区分大小写,按照字典序从小到大输出。
思路:直接的思路,不区分大小写,就先将所有字符统一成小写,学习运用stl 里set 可以去重的用法,同时set里面元素是有序的,还有个技巧,利用string,stringstream分割每行的字符串。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int N=1000005;
int inf=0x3f3f3f3f;
LL mod=1e9+7;
set<string>dict;
int main()
{
   string s,buf;
   while(getline(cin,s))
   {
       for(int i=0;i<s.length();i++)
         if(isalpha(s[i])) s[i]=tolower(s[i]);else s[i]=' ';
        stringstream ss(s);
        while(ss>>buf) dict.insert(buf);
   }
   for(set<string>::iterator iter=dict.begin();iter!=dict.end();++iter)
    cout<<*iter<<endl;
   return 0;
}

5-4 uva156 Ananagrams
题意:输入几行字符串,找到满足每个字母重新排列后都没有重复的单词,也不区分大小写,并按照字典序输出。
思路,由于每个单词要求重新排列后都不同,将他们排序小写化统一后,与出现次数建立一个映射关系,出现次数等于1 就满足。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int N=1000005;
int inf=0x3f3f3f3f;
LL mod=1e9+7;
string trans(string s)
{
    string ans=s;
    for(int i=0;i<ans.length();i++)
        ans[i]=tolower(ans[i]);
    sort(ans.begin(),ans.end());
    return ans;
}

int main()
{
    string s;
    vector<string>words;
    map<string,int>cnt;
    while(cin>>s)
    {
        string temp;
        if(s[0]=='#') break;
        words.push_back(s);
        temp=trans(s);
        if(!cnt.count(temp)) cnt[temp]=0;
        cnt[temp]++;
    }
    vector<string>ans;
    for(int i=0;i<words.size();i++)
        if(cnt[trans(words[i])]==1) ans.push_back(words[i]);
    sort(ans.begin(),ans.end());
    for(int i=0;i<ans.size();i++) cout<<ans[i]<<endl;
    return 0;
}

5-5 uva12096 The SetStack Computer
题意及思路:本题描述很高大上,其实最重要发现模拟过程中栈里存的是什么,一般认为栈里的元素不是整数变量或是字符串变量,而这里是集合,因为ADD操作特性是把栈顶出栈后当做元素放在下一个出栈的集合里,构成新的集合再入栈。所以这个集合就可以用set模拟,int表示每个元素的给他制定一个独一无二ID,还可以达到去重的功能。在判断这个元素ID是否已经存在,则又需要一个map《set《int》,int》”映射每一个存在的。详细模拟见代码。


#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int N=1000005;
int inf=0x3f3f3f3f;
LL mod=1e9+7;
stack< set<int> >stk;
map<set<int>,int>mp;
//vector<set<int> >Id;
set<int>s1,s2;
int num;
set<int> ID(set<int> x)
{
   if(mp.count(x))  return x;
    mp[x]=num++;
    return x;
}

void pop()
{
   s1=stk.top(); stk.pop();
   s2=stk.top(); stk.pop();
}

void push()
{
   set<int>s;
   stk.push(ID(s));
}

void dup()
{
    set<int>s=stk.top();
    stk.push(s);
}

void Union()
{
    pop();
    set<int>::iterator it;
    for(it=s1.begin();it!=s1.end();it++)
        s2.insert(*it);
    stk.push(ID(s2));
}
void Intersect()
{
    pop();
    set<int>s3;
    for(set<int>::iterator it=s1.begin();it!=s1.end();it++)
      if(s2.find(*it)!=s2.end()) s3.insert(*it);
    stk.push(ID(s3));
}

void add()
{
    pop();
    s2.insert(mp[s1]);
    stk.push(ID(s2));
}

int main()
{
    int T;cin>>T;
    while(T--)
    {
        int n;cin>>n;
        string s;
        num=0;
        mp.clear();
        while(!stk.empty()) stk.pop();
        s1.clear();s2.clear();
        for(int i=0;i<n;i++)
        {
            cin>>s;
            if(s[0]=='P') push();
            else if(s[0]=='D') dup();
            else if(s[0]=='U') Union();
            else if(s[0]=='I') Intersect();
            else if(s[0]=='A') add();
            cout<<stk.top().size()<<endl;
        }
        cout<<"***"<<endl;
    }
}

刘大神实现并集,交集借用了set自带set_union,set_intersection函数,代码量简化很多。还有一点不同是,刘大神stack《int》里存的是每个集合的ID。多加一个vector《set《int》》,方便找每个set《int》 ID.

#include<bits/stdc++.h>
using namespace std;
typedef set<int> Set;
map<Set,int>mp;
vector<Set>Id;
int ID(Set x)
{
    if(mp.count(x)) return mp[x];
    Id.push_back(x);
    return mp[x]=Id.size()-1;
}

#define ALL(x) x.begin(),x.end()
#define INS(x) inserter(x,x.begin())
int main()
{
    int T;cin>>T;
    while(T--)
    {
      int n;cin>>n;
      stack<int>stk;
      while(n--)
      {
          string s;
          cin>>s;
          if(s[0]=='P') stk.push(ID(Set()));
          else if(s[0]=='D') stk.push(stk.top());
          else
          {
              Set x1=Id[stk.top()];stk.pop();
              Set x2=Id[stk.top()];stk.pop();
              Set x;
              if(s[0]=='U')  set_union(ALL(x1),ALL(x2),INS(x));
              if(s[0]=='I')  set_intersection(ALL(x1),ALL(x2),INS(x));
              if(s[0]=='A')  {x=x2;x.insert(ID(x1));}
              stk.push(ID(x));
          }
          cout<<Id[stk.top()].size()<<endl;
      }
      cout<<"***"<<endl;
    }
}

5-6 uva540 TeamQueue
题意:有t个人排队,每次来一个人,如果有他的队友在排队,那么这个人就会插到他队友最后的位置。输出这个队伍,排队情况。
利用两个队列,第一个表示不同团体在整个队列的顺序情况,第二个表示每个个体在不同团体中情况,要用一个数组队列,表示第几个团体的队列。还需要一个个体对应团体的映射map《int,int》。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int N=1005;
int inf=0x3f3f3f3f;
LL mod=1e9+7;
int main()
{
    int t,cnt=0;;
    while(cin>>t&&t)
    {
        cout<<"Scenario #"<<++cnt<<endl;
        map<int,int>team;
        for(int i=0;i<t;i++)
        {
            int n;cin>>n;
            for(int j=0;j<n;j++)
            {
                int x;cin>>x;
                team[x]=i;
            }
        }
        queue<int>q,q2[N];//q是团体的在整个队列先后顺序,q2表示每个团体里面队列情况
        for(;;)
        {
            string s; cin>>s;
            if(s[0]=='S') break;
            if(s[0]=='D')
            {
                int a=q.front();
                cout<<q2[a].front()<<endl;
                q2[a].pop();
                if(q2[a].empty()) q.pop();
            }
            else if(s[0]=='E')
            {
                int num; cin>>num;
                if(q2[team[num]].empty()) q.push(team[num]);
                q2[team[num]].push(num);
            }
        }
        cout<<endl;
    }
}

5-7 uva 136 Ugly Number
题意:丑数是指不能被2 3 5以外的其他素数整除的数。把丑数从小到大排列起来: 1,2,3,4,5,6,8,9,10,12,…..求第1500个丑数是?
本题实现方法还有很多:最容易想到就是利用优先队列,加set判断,去重。如下。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int N=1000005;
int inf=0x3f3f3f3f;
LL mod=1e9+7;
const LL coeff[3]={2,3,5};
int main()
{
    set<LL>s; s.clear();
    priority_queue<LL,vector<LL>,greater<LL> >q;
    s.insert(1);q.push(1);
    for(int i=1;;i++)
    {
        LL x=q.top();q.pop();
        if(i==1500)
        {
            cout<<"The 1500'th ugly number is "<<x<<endl;
            break;
        }
        for(int j=0;j<3;j++)
        {
            LL x2=x*coeff[j];
            if(!s.count(x2)) {s.insert(x2),q.push(x2);}

        }
    }
    return 0;
}

5-8 uva 400 Unix is
题意:给你n个字符串,左对齐的方式,按列优先以每六十个单位为一行输出所有字符串,每列之间的距离是所有字符串中最长的长度的加二,最后一列之后没有空格。
思路,输入字符串的时候记录最长长度,先算一行有多少列,根据总个数算多少行,输出。考察模拟代码工地,有一个技巧,这里重复实现将一个字符串输出后,再输出空格的功能,所以编写一个函数,极大简化代码。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int N=110;
int inf=0x3f3f3f3f;
LL mod=1e9+7;
string s[N];
void print(const string &s,int len,char extra)
{
    cout<<s;
    for(int i=0;i<len-s.length();i++)
        cout<<extra;
}

int main()
{
    int n;
    while(cin>>n)
    {
       int maxx=0;
       for(int i=0;i<n;i++)
       {
           cin>>s[i];
           maxx=max(maxx,(int)s[i].length());
       }
       int cols=62/(maxx+2),row=(n-1)/cols+1;
       sort(s,s+n);
       print("",60,'-');
       cout<<endl;
       for(int i=0;i<row;i++)
       {
         for(int j=0;j<cols;j++)
         {
            int idx=j*row+i;
            if(idx<n) print(s[idx],j==cols-1?maxx:maxx+2,' ');
         }
         cout<<endl;
       }

    }
}

5-9 uva 1592 Database
题意 :给一个n行m列字符串,问你是否存在两个不同行r1,r2,两个不同列c1,c2,使得 (r1,c1),(r2,c1)与(r1,c2),(r2,c2)相等。
直接写一个四重枚举,10000*10000*10*10绝壁TLE。
解决方法:这里有个技巧,判断字符串是否相同需要时间比较长,我们就先把每个位置字符串先预处理对应成数字编号,map《string,int》判重,给他赋编号,就构建一个n行m列的整数数组。
先枚举c1,c2,两列,然后从上往下扫描,每碰到一个新的行r,把它的两列,作为一个二元组,放入map《pair《int ,int 》,int》,左边赋值n行m列位置的编号,右边赋值这个编号所处的行位置,如果有重复的,就说明从c1,c2两列的的这两行相同,直接输出结果。
复杂度:10*10*10000 不会超时。

#include<cstring>
#include<cstdio>
#include<vector>
#include<map>
#include<string>
using namespace std;
const int N=10010,M=20;
int main()
{
   int n,m;
   while(scanf("%d%d",&n,&m)!=EOF)
   {
       getchar();
       map<string, int>dict;
       char entry[110],coma;
       int db[N][M],cnt=1;
       for(int i=0;i<n;i++)
       {
           for(int j=0;j<m-1;j++)
           {
               scanf("%[^,]%c",entry,&coma);
               string s(entry);
               if(!dict.count(s)) dict[s]=cnt++;
               db[i][j]=dict[s];
           }
           scanf("%[^\n]",entry);
           getchar();
           string s(entry);
           if(!dict.count(s)) dict[s]=cnt++;
           db[i][m-1]=dict[s];
       }
       int ok=0;
       for(int c1=0;c1<m;c1++)
       {
           for(int c2=c1+1;c2<m;c2++)
           {
               map<pair<int,int>, int>vis;
               for(int r2=0;r2<n;r2++)
               {
                   pair<int,int>p(db[r2][c1],db[r2][c2]);
                   if(vis.count(p))
                   {
                       ok=1;
                       printf("NO\n%d %d\n %d %d\n",vis[p]+1,r2+1,c1+1,c2+1);
                       break;
                   }
                   vis[p]=r2;
               }
               if(ok) break;
           }
           if(ok) break;
       }
       if(!ok) printf("YES\n");
   }
   return 0;
}

(未完)
后记:暂时先补充这些题解,加深巩固,这一章后面还做了几道习题,题很好,但由于没有时间了…..(还有一堆别的作业,机组卷子,机组实验,概率论卷子,数据结构卷子,TM这些还都要期中考试,数据结构的几个算法,笔试卷子题也没练习过).这段时间要反思一下时间都去哪呢(打炉石)..我会说开学到现在就陆陆续续水了这点东西…
今天下午传来一个好消息,组长田博士亚洲区现场赛两枚铜牌,还有一场可惜银牌!!!!(恭喜学长)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值