紫薯第5章学习 STL(先更新eg题部分)

sstream学习(~~留坑中。。。~~EG题其实有涉及的)


模板 templete 体会。(留坑中。。。


eg题部分STL基础

Where is the Marble? UVA - 10474sort && lower_bound

在这里插入图片描述
在这里插入图片描述

题意:

给你n个石头,先排好序。
之后有m次询问,问你x石头是否存在,并在上面的有序表找到石头的下标。

思路:

sort && 二分

反思:

好像 iterator it 没有减法运算。(不能像数组一样)

AC

#include <iostream>
#include <set>
#include <algorithm>
#define For(i,x,y) for(register int i=(x); i<=(y); i++)
using namespace std;
//multiset<int>s;读取不了位置,哎哎。
const int maxn=1e4+10;
int a[maxn];
int main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int n,m,kase=0;
    while(cin>>n>>m,n|m)
    {
        //s.clear();
        int x;
        For(i,1,n)cin>>a[i];
        //{
          //  cin>>x;
       //     s.insert(x);
        //}
        //multiset<int>::iterator it;
        sort(a+1,a+1+n);
        cout<<"CASE# "<<++kase<<":"<<'\n';
        For(i,1,m)
        {
            cin>>x;
          //  it=s.lower_bound(x);//这里的指针不能相减。
            int pos=lower_bound(a+1,a+1+n,x)-a;
            if(pos==n+1||a[pos]!=x)cout<<x<<" not found"<<"\n";
            else cout<<x<<" found at "<<pos<<"\n";
           // if(a[pos]==x)cout<<x<<" found at "<<pos<<"\n";
           //紫薯的但是我觉得如果没初始化,可能有bug
            //else cout<<x<<" not found"<<"\n";
        }
    }
    return 0;
}

The Blocks Problem UVA - 101vector,我的太丑了,就放紫薯的吧)

在这里插入图片描述
在这里插入图片描述

题意:

从左到右有 n 个木块,编号为0~ n - 1, 要求模拟一下4种操作(下面的a和b都是编号)

  1. move a onto b: 把 a 和 b 上方的木块全部归位,然后把 a 摞到 b 上面
  2. move a over b: 把 a 上方的木块全部归位,然后把 a 放在 b 所在木块堆的顶部
  3. pile a onto b: 把 b 上方的木块全部归位,然后把 a 及上面的木块 摞到 b 上面
  4. pile a over b: 把 a 及上面的木块 摞到 b 所在木块堆的顶部

思路:

由于每个堆的高度 不确定,所以适合用 vector 来保存
开一个vector【】,去模拟,就像stack(栈一样)。

反思:

  1. 本题有四个操作如果完全独立地处理各命令,代码就会变得冗长而且容易出错。更好地办法是提取出指令间的共同点编写函数,减少重复代码
  2. resize()有时也可以用来删除数。
for(int i=h+1; i<pile[p].size(); i++)
    {
        int pos=pile[p][i];
        pile[pos].pb(pos);
    }
    pile[p].resize(h+1);//delete.
for(int i=h; i<pile[p].size(); i++)
    {
        pile[p2].pb(pile[p][i]);
    }
    pile[p].resize(h);
  1. ==vector也可以下标访问,==哎,用vector老是忘,直接去下标了。

  2. 比较字符可以在开头定义cosnt

const string t1="onto";
const string t2="move";

笔记:

  1. vector 之间可以直接赋值,或者作为函数的返回值
  2. 用empty测试是否为空。

AC

#include <iostream>
#include <vector>
#include <string>
#define pb push_back
#define sz size()
#define For(i,x,y) for(register int i=(x); i<=(y); i++)
using namespace std;
vector<int>pile[25];
const string t1="onto";
const string t2="move";
//后面比较用的
int n,a,b;
void find_block(int a, int &p, int &h)
{
    for(p=0; p<n; p++)
    {
        for(h=0;h<pile[p].size();h++)if(pile[p][h]==a)return;
    }
}//找到木块,返回高度,和在哪一堆。
void clear_above(int p ,int h)
{
    for(int i=h+1; i<pile[p].size(); i++)
    {
        int pos=pile[p][i];
        pile[pos].pb(pos);
    }
    pile[p].resize(h+1);//delete.
    //最后再清除
}//清楚h上面的木块,
void pile_onto(int p, int h, int p2)
{
    for(int i=h; i<pile[p].size(); i++)
    {
        pile[p2].pb(pile[p][i]);
    }
    pile[p].resize(h);
}//把p高度h(可能有以上)移动到p2上
void printf()
{
    For(i,0,n-1)
    {
        cout<<i<<":";
        for(int j=0; j<pile[i].sz;j++)cout<<' '<<pile[i][j];
        cout<<'\n';
    }
}//输出
int main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n;
    string s1,s2;
    For(i,0,n-1)pile[i].pb(i);
    //cout<<"OK"<<endl;
    while(cin>>s1&&s1[0]!='q')
    {
        cin>>a>>s2>>b;
       // cout<<"Ok"<<endl;
        int pa,pb2,ha,hb;
        find_block(a,pa,ha);
        find_block(b,pb2,hb);
        if(pa==pb2)continue;
        if(s2==t1)clear_above(pb2,hb);
        if(s1==t2)clear_above(pa,ha);
        pile_onto(pa,ha,pb2);
    }
    printf();
    return 0;
}

Andy’s First Dictionary UVA - 10815set

在这里插入图片描述
在这里插入图片描述

题意:

有一个文本,要你找到所有的单词,之后按照字典序输出,不重复。(不区分大小写)

思路:

set 有序的集合,

  1. 由于可能带标点,所以把标点变成space,之后再用stringstream得到各个单词。
if(isalpha(s[i]))s[i]=tolower(s[i]);
//判断是否是字母,以及转换为小写。
 else s[i]=' ';
 stringstream ss(s);
 while(ss>>buf)text.insert(buf);//在ss中插入

反思:

  1. isalpha() 判断是否是字母
  2. tolower(),转换为小写。
  3. stringstream ss(s) 的操作
stringstream ss(s);
 while(ss>>buf)text.insert(buf);//在ss中插入
  1. 读到EOF可以 while(cin>>s)

AC

#include <iostream>
#include <string>
#include <sstream>
#include <set>
using namespace std;
set<string>text;
int main()
{
    string s,buf;
    while(cin>>s)
    {
        for(int i=0; i<s.size(); i++)
        {
            //if((s[i]>='a'&&s[i]<='z')||(s[i]>='A'&&s[i]<='Z'))s[i]=tolower(s[i]);
            if(isalpha(s[i]))s[i]=tolower(s[i]);
            //判断是否是字母,以及转换为小写。
            else s[i]=' ';
            //把标点直接变成space
        }
        stringstream ss(s);
        while(ss>>buf)text.insert(buf);//在ss中插入
    }
    set<string>::iterator it=text.begin();
    for(it;it!=text.end();it++)cout<<*it<<'\n';
    return 0;
}

18731 最接近的值

Description
查找特定的值是一种常见的操作,当数据量较大时,往往需要使用高效的结构和查找算法。
n个整数组成的序列,请输出所有元素左侧与它值最为接近的值,我们定义“最接近”为两数之差的绝对值最小。
例如序列 5 1 4 2,1最接近值为5,4最接近值为5,2最接近值为1。
特别的,第一个数的最接近值为它自身。
如果一个数左侧有两个不同的值,绝对值差都是最小。例如3的左边出现了1和5,我们认为值较大的5为最接近值
格式第一行一个整数n。(1<=n<=100000)
第二行n个整数,均为int范围。

输出格式一行,n个整数,为输入序列对应元素的最接近值。

输入样例
4
5 1 4 2

输出样例
5 5 5 1

AC

#include <iostream>
#include <set>
#include <vector>
#include <cmath>
#include <algorithm>
#define For(i,x,y) for(register int i=(x); i<=(y); i++)
using namespace std;
const int INF=0x3f3f3f3f;
set<int>s;
vector<int>ans;
int main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int n,x,pos,temp,dis=0;
    set<int>::iterator it;
    cin>>n;
    For(i,1,n)
    {
        dis=INF;
        cin>>x;
        if(i==1)
        {
            ans.push_back(x);
            s.insert(x);
            continue;
        }
        it=s.lower_bound(x);
        if(it!=s.end()&&*it>=x)dis=*it-x,temp=*it;
        if(it!=s.begin())
        {
            it--;//cout<<*it<<endl;
            if(dis==INF||dis>x-*it)temp=*it;
        }
        ans.push_back(temp);
        s.insert(x);
    }
    For(i,0,n-1)cout<<ans[i]<<' ';
    return 0;
}

引进map前,先看看“经典数对”问题(其实有两种统计方法,这里只介绍其中一种,另外一种见(其实就数学)一道eg题

下面的解法是边读边算。另一种解法是先全部读入再算。

18727 数对问题一

时间限制:1000MS 代码长度限制:10KB(规模小,直接开数组

Description
一个长度为N的正整数序列,现在需要计算出有多少对数字的差的绝对值为C。
注意只要位置不同就认为是不相同的数对。

输入格式第一行,两个整数 N, C。(1=<N<=10000),(1=<C<=10000)
第二行,N个正整数a1…an。 (1=<ai<=10000)

输出格式仅一行,满足条件的数对的个数。

输入样例
4 1
1 2 3 1

输出样例
3

提示(a1,a2),(a2,a3),(a2,a4)共3个数对满足条件。

#include <iostream>
#define For(i,x,y) for(register int i=(x); i<=(y); i++)
using namespace std;
const int maxn=1e5+10;
int vis[maxn];
typedef long long ll;
int main()
{
    ll ans=0;
    int n,c,a;
    cin>>n>>c;
    For(i,1,n)
    {
        cin>>a;
        vis[a]++;
        if(a>=c)ans+=vis[a-c];
        ans+=vis[a+c];
    }
    cout<<ans<<endl;
    return 0;
}

18728 数对问题二

时间限制:1000MS 代码长度限制:10KB(规模大,要开map)(set&&lower_bound)(东哥)

Description
此题目与数对问题一的唯一区别为序列中元素的取值范围。
一个长度为N的正整数序列,现在需要计算出有多少对数字的差的绝对值为C。
注意只要位置不同就认为是不相同的数对。

输入格式第一行,两个整数 N, C。(1=<N<=10000),(1=<C<=10000)
第二行,N个正整数a1…an。 ai为int范围内的正整数。

输出格式仅一行,满足条件的数对的个数。

输入样例
4 1
1 2 3 1

输出样例
3

提示(a1,a2),(a2,a3),(a2,a4)共3个数对满足条件。

#include <iostream>
#include <map>
#define For(i,x,y) for(register int i=(x); i<=(y); i++)
using namespace std;
typedef long long ll;
map<ll,ll>ma;
int main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    ll ans=0,a;
    int n,c;
    cin>>n>>c;
    For(i,1,n)
    {
        cin>>a;
        if(a-c>=0&&ma[a-c])ans+=ma[a-c];
        ans+=ma[a+c];
        ma[a]++;
    }
    cout<<ans<<endl;
    return 0;
}

Ananagrams UVA - 156map

在这里插入图片描述
在这里插入图片描述

题意:

输入一个单词文本,找出所有满足下面条件的单词。该单词不能通过字母重排,得到输入文本中的另一个单词。判断是否满足条件时,字母不分大小写,但在输入时应保留输入文中的大小写,按照字典序进行排列(所有大写字母在小写字母的前面

思路:

  1. 本题说重排序,也就是说可以把每个单词内排好,之后放在map里记录。
    eg cat 的 自己排序就是,act,后面如果出现act,那么cat肯定不是。
  2. 为了完成1,可以先把原文本存起来,之后对现有的文本进行标准化。

反思

  1. 字符串本身就可以 sort()
  2. 当时做的时候我还手写桶排,去排(哎哎哎啊)。

AC

#include <iostream>
#include <cstring>
#include <vector>
#include <string>
#include <map>
#include <algorithm>
using namespace std;
vector<string>v;
vector<string>ans;
map<string,int>ma;
string stand(string s)
{
    for(int i=0; i<s.size(); i++)s[i]=tolower(s[i]);
    sort(s.begin(),s.end());
    return s;
}
int main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    string s;
    while(cin>>s)
    {
        if(s[0]=='#')break;
        v.push_back(s);
        s=stand(s);
     //   cout<<s<<'\n';
        if(!ma.count(s))ma[s]=0;
        ma[s]++;
    }
   // for(int i=0; i<v.size(); i++)cout<<v[i]<<endl;
    for(int i=0; i<v.size(); i++)
    {
        string temp=stand(v[i]);
        if(ma[temp]==1)ans.push_back(v[i]);
    }
    sort(ans.begin(),ans.end());
    for(int i=0; i<ans.size(); i++)cout<<ans[i]<<'\n';
    return 0;
}

The SetStack Computer UVA - 12096(stack)

在这里插入图片描述
在这里插入图片描述

题意:

有一个专门为了集合运算而设计的“集合栈”计算机。该机器有一个初始为空的栈,并且支持以下操作。

  1. PUHS:空集“{ }“入栈。
  2. DUP:把当前栈顶元素复制一份再入栈。
  3. UNION: 出栈两个集合,然后把两者的并集入栈。
  4. INTERSECT:出栈两个集合然后把两者的交集入栈。
  5. ADD: 出栈两个集合,然后把先出栈的集合加到后出栈的集合中,把结果入栈。
    每次操作后,输出栈顶集合的元素个数。

反思&题解

本题的集合并不是简单的整数集合或者字符串集合,而是集合的集合。为了方便起见,此处为每一个不同的集合分配一个唯一的ID,则每个集合都可以表示成所包含元素的ID集合。(特殊地:空集的id为0).

#define ALL(x) x.begin(), x.end();
//先写两个宏,方便后面的操作。
#define INS(x) inserter(x,x.being())
//这里表示插入集合(inserter插入者)的宏、

  1. 对于集合交并可以调用:algorithm里的
    set_union(ALL(x1), ALL(x2), INS(x))
    set_intersection(ALL(x1), ALL(x2), INS(x))
  2. 可以#define SET set< int >(后面调用set时,比较方便。)
  3. SET()可以表示空集。即(set< int >() 里面放一个元素),空集套空集,也是有元素了。本题是先把空集压入,之后就看是否会产生新集合,而新集合的产生只和操作345有关。而add操作是可以产生新集合的,如果空集套空集,就让这个空集里发一个元素0,表示有空集
    在这里插入图片描述
    由图,可以发现,之前因为空集,所以并没有输出,而当执行ADD后,即空集套空集,使得一个空集里面有一个空集。(如果这个新集合放到一个新集合里,那么也是对应它的标号。)

AC

#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <algorithm>
#define Set set<int>
#define For(i,x,y) for(register int i=(x); i<=(y); i++)
#define ALL(x) x.begin(),x.end()
//先写两个宏,方便后面的操作。
#define INS(x) inserter(x,x.begin())
//这里表示插入集合(inserter**插入者**)的宏、
using namespace std;
map<Set,int>idcach;
//可以用map记录一个集合是否出现过,如果出现过,就返回该集合的下标。
vector<Set>setcach;
//记录集合的下标
int id(Set x)
{
    if(idcach.count(x))return idcach[x];
    setcach.push_back(x);
    return idcach[x]=setcach.size()-1;//没有出现过,赋值,并返回这个新集合的下标。
}
int main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int t;
    cin>>t;
    while(t--)
    {
        idcach.clear();
        setcach.clear();
        stack<int>st;//栈里放集合(就可以转换成放集合的下标了)
        int n;
        string s;
        cin>>n;
        For(i,1,n)
        {
            cin>>s;
            if(s[0]=='P')st.push(id(Set()));
            else if(s[0]=='D')st.push(st.top());
            else
            {
                Set x1,x2,x;
                x1=setcach[st.top()];st.pop();
                x2=setcach[st.top()];st.pop();
                if(s[0]=='U')set_union(ALL(x1),ALL(x2),INS(x));
                else if(s[0]=='I')set_intersection(ALL(x1),ALL(x2),INS(x));
                else {x=x2;x.insert(id(x1));}//把1这个集合的下标插入到集合2里。
                st.push(id(x));
            }
           // Set:: iterator it=setcach[st.top()].begin();
           // for(it;it!=setcach[st.top()].end();it++)cout<<*it<<' ';
           // cout<<endl;
            cout<<setcach[st.top()].size()<<endl;
            //每次输出,就弹出下标(对应哪个集合),
            //之后去setcach里找到集合,之后返回这个集合元素的个数。
        }
        cout<<"***"<<endl;
    }
    return 0;
}

和排序

思路:

后缀维护+模拟
详见

AC(1e6)

#include <iostream>
#include <stack>
#include <queue>
#define For(i,x,y) for(register int i=(x); i<=(y); i++)
using namespace std;
const int maxn=1e5+10;
stack<int>st;
int n,x,a[maxn],suf[maxn];//,pre[maxn]maxx,vis[maxn],t,
int main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n;
    For(i,1,n)cin>>a[i];
    for(int i=n; i>=1; i--)
    {
        if(a[i]>suf[i+1])suf[i]=a[i];
        else suf[i]=suf[i+1];
    }
    For(i,1,n)
    {
        x=a[i];
        while(!st.empty()&&suf[i]<st.top())//suf【i】就是优化,省了0n查询
        {
            cout<<st.top()<<' ';st.pop();
        }
        st.push(x);
    }
    while(!st.empty())//把剩下的输出
    {
        cout<<st.top()<<' ';
        st.pop();
    }
    return 0;
}

Team Queue UVA - 540(二维队列

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

思路:

简单模拟。

  1. 建立一个团队队列,(只放团队的编号)
  2. 每个团队单独看成一个队列
  3. 在输入的时候,用map把每个队员的团队都标价一下。

收获

  1. 队列可以开二维
  2. while(cin>>T,T)(c++写法,当T为0时)

AC

#include <iostream>
#include <queue>
#include <map>
#define For(i,x,y) for(register int i=(x); i<=(y); i++)
using namespace std;
int t;
queue<int>q[1010];
queue<int>qm;
map<int,int>ma;
void init()
{
    while(!qm.empty())qm.pop();
    For(i,1,t)while(!q[i].empty())q[i].pop();
    ma.clear();
    int num=0,x;
    For(i,1,t)
    {
        cin>>num;
        For(j,1,num)
        {
            cin>>x;
            ma[x]=i;
        }
    }
}
void work()
{
    string s;
    while(cin>>s)
    {
        int x,num;
        if(s[0]=='S')break;
        else if(s[0]=='E')
        {
            cin>>x;
            num=ma[x];
            if(q[num].empty())qm.push(num);
            q[num].push(x);
        }
        else
        {
            num=qm.front();
            cout<<q[num].front()<<endl;
            q[num].pop();
            if(q[num].empty())qm.pop();
        }
    }
}
int main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int kase=0;
    while(cin>>t,t)
    {
        cout<<"Scenario #"<<++kase<<endl;
        init();
        work();
        cout<<endl;
    }
    return 0;
}

Ugly Numbers UVA - 136优先队列

在这里插入图片描述

思路:

  1. 可以找到规律,对于任意丑数x:2x,3x,5x也是丑数。
  2. 这就可以转换成队列的问题了。
  3. 对于入队的要标记这个丑数生成过
  4. 每次都拿最小的丑数去更新。
  5. 所以用优先队列去维护。

反思

  1. 不开longlong见祖宗
  2. 对于转换成队列的问题了。 这个过程还不是很熟练。

AC

#include <iostream>
#include <queue>
#include <map>
#define For(i,x,y) for(register int i=(x); i<=(y); i++)
using namespace std;
typedef long long ll;
const int cao[3]={2,3,5};
ll cnt=0,top;
map<ll,ll>vis;
int main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    priority_queue<ll,vector<ll>,greater<ll> >q;
    vis[1]=1;
    q.push(1);
    while(1)
    {
        top=q.top();
        For(i,0,3-1)
        {
            if(!vis[cao[i]*top])
            {
                q.push(cao[i]*top);
                vis[cao[i]*top]=1;
            }
        }
        cnt++;
        if(cnt==1500)break;
        q.pop();
    }
    cout<<"The 1500'th ugly number is "<<q.top()<<'.'<<endl;
    return 0;
}

Unix ls UVA - 400(sort&&string)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

题意:

把输入的n个串排序,再输出。

思路:

找到最大串,maxx
之后

  1. col=(60-maxx)/(maxx+2)+1(向下取整)
  2. row=(n+col-1)/col(向上取整)

反思

string 的 sort

  1. 对于string s【100】不可以直接sort(s.begin(),s.end())
  2. 而要sort(s,s+n)
  3. 或者上vector< string >

紫薯一个地方强调好多次了,重复操作写函数,减少错误的可能

AC

#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
using namespace std;
string s[110];
void print(const string&s,int len, char temp)//输出的写法
{
    cout<<s;
    for(int i=0; i<len-s.length(); i++)cout<<temp;
}
int main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    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() ));
        }
        sort(s,s+n);//这里假如是vector就可以begin,end
        print("",60,'-');
        cout<<endl;
        int col=(60-maxx)/(maxx+2)+1;
        int row=(n+col-1)/col;
        for(int r=0; r<row; r++)
        {
            for(int c=0; c<col; c++)
            {
                int indx=c*row+r;
                if(indx>=n)continue;//够了就别输出了。
                print(s[indx],(c==col-1)?maxx:maxx+2,' ');
            }
            cout<<endl;
        }
//
    }
    return 0;
}

Database UVA - 1592(map&&string)

在这里插入图片描述
在这里插入图片描述

题意:

给你一个文本。要你看是否存在有四个string,
满足:(r1,c1)=(r2,c1)和(r1,c2)=(r2,c2)

思路

  1. 枚举列c1,c2.
  2. 之后扫一遍行,如果当前二元组之前出现过,就NO。(map存二元组的行号)
  3. 最后都没找到,就yes

反思

map映射,编号

  1. 虽然二元组直接string也可以,但map中string的比较费时间(取决于string长度)。
  2. 所以可以先映射每个string为int。之后就是int的比较(给string编号)

sstream的妙用(输入),(不过我没用,直接暴力了哈哈)

这里的 getline(input, temp, ‘,’) 后面那个’,‘元素是区间。

getline(cin, line); stringstream input(line); // 字符串流
while (getline(input, temp, ',')) ;a[i][++cnt]=get_id(temp);

getline也要吃回车

ios关闭后,字符题有意想不到的结果用一次自闭一次

AC

#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <cstring>
#include <cstdio>
#define mp make_pair
#define mst(x,a) memset(x,a,sizeof(x))
#define For(i,x,y) for(register int i=(x); i<=(y);  i++)
using namespace std;
typedef pair<int,int>pa;
map<pa,int>ma;
map<string,int>idcach;
vector<string>cach;
int get_id(string s)
{
    if(idcach.count(s))return idcach[s];
    cach.push_back(s);
    return idcach[s]=cach.size()-1;
}
int a[10010][11],n,m,pre=0,cnt;
void init()
{
    mst(a,0);
    cach.clear();
    idcach.clear();
    For(i,1,n)
    {
        string temp,line;
        pre=cnt=0;
        getline(cin, line);
       // cout<<line.length()<<endl;
        for(int j=0; j<=line.length(); j++)
        {
            //int last=line.size()-1;
            if(line[j]==','||j==line.length())
            {
                temp=line.substr(pre,j-pre);
                cnt++;
                a[i][cnt]=get_id(temp);
                //cout<<temp<<' '<<get_id(temp)<<endl;
                pre=j+1;
            }
        }
        //cout<<endl;
    }
}
void solve()
{
    for(int i=1; i<=m; i++)
    {
        for(int j=i+1; j<=m; j++)
        {
            ma.clear();
            for(int k=1; k<=n; k++)
            {
                if(ma.count(mp(a[k][i],a[k][j]) ) )
                {
                    cout<<"NO"<<endl;
                    cout<<ma[mp(a[k][i],a[k][j])]<<' '<<k<<endl;
                    cout<<i<<' '<<j<<endl;
                    return ;
                }
                ma[mp(a[k][i],a[k][j])]=k;
            }
        }
    }
    cout<<"YES"<<endl;
    return ;
}
int main()
{
    //ios::sync_with_stdio(0);
    //cin.tie(0);
    //cout.tie(0);
    //原来是标准输入输出的问题,吐了。一直读取错误。(看来要标准输入,输出,读字符串时)
    while(cin>>n>>m)
    {
       // cout<<n<<' '<<m<<endl;
        getchar();//!!!
        init();
        /*
        For(i,1,n)
        {
            For(j,1,m)cout<<a[i][j]<<' ';
            cout<<endl;
        }
        */
        solve();
    }
    return 0;
}
/*
3 3
How to compete in ACM ICPC,Peter,[email protected]
How to win ACM ICPC,Michael,[email protected]
Notes from ACM ICPC champion,Michael,[email protected]
2 3
1,Peter,[email protected]
2,Michael,[email protected]
*/

PGA Tour Prize Money UVA - 207(大模拟毒瘤题目,字符的读入&&细节处理)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

思路:

  1. 先把所有选手前两轮的得分进行排名。(题目保证一定有70人晋级)
  2. 接下来四轮总分再进行一次排序。
  3. 之后就是颁奖。
  4. 最后输出。

反思&&收获

本题的输入一如既往要用getline

  1. 先吃回车:getchar。
  2. 之后读取一行:getline(cin,line)
  3. 由于名字是要读取21个字符,所以
play[i].name=line.substr(0,21);//输入名字
  1. 业余的判断
play[i].amateur=(find(line.begin(),line.end(),'*')!=line.end());
  1. 把字符string转换为int stoi
  2. 把int转换为stringto_string(int)

输入X2

  1. 也可以把前20个给读取了fgets(char*,size,stdin)
  2. 之后用scanf(”%s“)读取。转换就行。

输出

printf(“%-10d“)输出时后面不够10.右补(很符合左+,右-
printf(”%10d“)输出时,左边不够10,左补。

AC

#include <iostream>
#include <cstring>
#include <string>
#include <sstream>
#include <cstdio>
#include <algorithm>
#include <bits/stdc++.h>
#define For(i,x,y) for(register int i=(x); i<=(y); i++)
using namespace std;
const int maxn=200;
const int maxt=50;
//const int DQ=999999;
const double eps=1e-8;
struct player
{
    string name;
    double money;
    int place,all_2,all_4,run[4];//all_2存第一轮,all_4为颁奖做准备
    int run_num=0;
    bool amateur=false,T=false,prize=false;
} play[maxn];
void newplay(player & a)
{
    a.prize=a.amateur=a.T=a.run_num=a.all_2=a.all_4=0;
    a.place=0;
    a.money=0.0;
    For(i,0,4-1)a.run[i]=-1;
}
bool cmp1(const player &a,const player &b)
{
    return a.all_2<b.all_2;
}
bool cmp2(const player &a, const player &b)
{
    if(a.run_num!=b.run_num)
        return a.run_num>b.run_num;
    else if(a.all_4!=b.all_4)
        return a.all_4<b.all_4;
    return a.name<b.name;
    ///use char[]
    //strcmp(a.name,b.name)<0 a<b;
}
double purse[maxn];
int n;
void init()
{
    For(i,0,70)cin>>purse[i];
    cin>>n;
    getchar();
    string line;
    For(i,1,n)
    {
        getline(cin,line);
        newplay(play[i]);//初始化结构
        play[i].amateur=(find(line.begin(),line.end(),'*')!=line.end());//判断是否业余。
        //字符串查找
        play[i].name=line.substr(0,21);//输入名字
        For(j,0,4-1)
        {
            string hole=line.substr(21+j*3,2);
            if(hole=="DQ")
                break;//如果DQ,那么犯规,后面的得分没有了。
            play[i].run[j]=stoi(hole);
            ++play[i].run_num;
            if(j<2)
                play[i].all_2+=play[i].run[j];
            play[i].all_4+=play[i].run[j];
        }
        play[i].all_2=(play[i].run_num<2)?400:play[i].all_2;//如果轮数小于两轮,那么肯定不可能获奖,直接把它安排到最后面。
        //因为输入保证有70人会进级
    }
}
void divide()
{
    int cnt=1;
    for(int i=1; i<=n; )//For(i,1,n)
    {
        int j=i,profession=0;
        for(; j<=n&&play[j].all_4==play[i].all_4; j++)
        {
            if(!play[j].amateur)
                ++profession,play[j].prize=(cnt<=70);
        }//统计同名次,可能获得奖金的人数
        double cur_purse=0.0;
        for(int k=0; k<profession&&cnt<=70; k++)
            cur_purse+=purse[cnt++];
        cur_purse*=purse[0]/100/profession;
        For(k,i,j-1)
        {
            play[k].place=i;
            play[k].money=play[k].prize?cur_purse:0.0;
            play[k].T=!play[k].amateur&&profession>1&&play[k].prize;
        }
        i=j;
    }
}
void print()
{
    int cot=0;
    printf("Player Name          Place     RD1  RD2  RD3  RD4  TOTAL     Money Won\n");
    printf("-----------------------------------------------------------------------\n");
    For(i,1,n)
    {
        cout<<play[i].name;
        string place="";
        if(play[i].run_num==4)
            place=to_string(play[i].place)+( (play[i].T)?"T":"");
        printf("%-10s",place.c_str());
        //if(play[i].place<10)cot=9;
        //else if(play[i].place<100)cot=8;
        //else cot=7;
        //cout<<play[i].place;
        //if(play[i].T&&play[i].run_num==4)cot--,cout<<"T";
        // For(j,1,cot)cout<<' ';
        For(j,0,4-1)
        {
            if(play[i].run[j]==-1)
                cout<<"     ";
            else
                printf("%-5d",play[i].run[j]);
        }
        if(play[i].run_num<4)
            cout<<"DQ"<<'\n';
        else if(!play[i].prize||play[i].amateur)
            cout<<play[i].all_4<<'\n';
        else
            printf("%-10d$%9.2f\n",play[i].all_4,play[i].money);
    }
}
int main()
{
    int t,kase=0;//cout<<(0.0==0.00)<<endl;
    cin>>t;
    while(t--)
    {
        if(kase++)
            cout<<endl;
        init();
        sort(play+1,play+1+n,cmp1);//the first cut
        int temp=70;
        while(temp+1<=n&&play[temp+1].all_2==play[70].all_2)
            temp++;//找到70名以后,同名次的。
        n=temp;
        sort(play+1,play+1+n,cmp2);//筛选出可能获奖者
        divide();//开始颁奖
        print();
    }
    return 0;
}

The Letter Carrier’s Rounds UVA - 814(又是一道模拟毒瘤,这里放上紫薯的标程)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

题意:

邮件格斯为:user@MTA
当一个人以 user1@MTA1 发给另外一个人时user2@MTA2.这两个MTA将会通信。

输入:

  1. 先是每个MTA的用户列表。
  2. 对于每个发送请求(输入发送者和接收者列表),按顺序输出所有MTA之间的SMTP(简单邮件协议)交互。(详见题目)
  3. MTA1连接收件人的MTA2的顺序应该与输入“第一次出现的顺序”一致。

思路:

  1. 对于第一次输入每个MTA的用户列表
    (用一个set< string > addr,是为了保存可能的用户的邮箱地址,方便后面输出时,查找是否有该用户。addr.count(adress))放在有序表里,我觉得而是为了查找,方便
  2. 对于输入,要根据邮箱地址,处理出收件人,(后面也有重复的操作),所以定义一个函数。
  3. map< string ,vector < string > >dest 定义,相当于把MTA1需要发送的用户地址放入。之后看用户是否存在时,再与1中的set相比较,看是否有这个用户。
  4. 还要定义一个vector< string > mta为了存放MTA1要连接的其他MTA2.(这里是为了,题目的输出要求与输入顺序一致),再定义一个map< string > vis去记录,当前MTA,是否在vector里
  5. 输出时,遍历vector < > mta即可。对于每个MTA1所连接的MTA,要看dest【MTA】里存的用户地址了。之后输出时,要判断用户是否存在。

反思

  1. map可以key为string,而value为一个数组
  2. string可以不用初始化,直接加字符操作。也可以加换行。
  3. find函数,对于string 返回的好像可以是第几个。而set里,返回的是指针。
  4. 本题要小心空格的输出。

AC(紫薯AC代码)

#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <map>
using namespace std;
void parse_address(const string &s, string &user, string &mta)
{
    int k=s.find("@");//找到“@”,并返回指向它的pos位置,
    user=s.substr(0,k);//由于从0开始,所以可以这样。
    mta=s.substr(k+1);
}
int main()
{
    int k;
    string s,t,user1,mta1,user2,mta2;
    set<string> adder;//存放所有的地址。
    //
    //输入所有MTA,转换为地址。
    while(cin>>s&&s!="*")//the first is MTA must be read.
    {
        cin>>s>>k;
        while(k--){cin>>t;adder.insert(t+"@"+s);}
    }
    //solve
    while(cin>>s&&s!="*")
    {
        parse_address(s,user1,mta1);//deal with the sender
        //
        vector<string>mta;//link all mta
        map<string,vector<string> >dest;//where each MTA should send to.
        set<string>vis;
        while(cin>>t&&t!="*")
        {
            parse_address(t,user2,mta2);
            if(vis.count(t))continue;
            vis.insert(t);
            if(!dest.count(mta2)){mta.push_back(mta2);dest[mta2]=vector<string>();}
            dest[mta2].push_back(t);
        }
        getline(cin,t);//it can get "*" and "ENTER"
        //
        //read the text of the mail
        string data;
        while(getline(cin,t)&&t[0]!='*')data+="     "+t+"\n";
        //
        for(int i=0; i<mta.size(); i++)
        {
            string mta2=mta[i];
            vector<string> users=dest[mta2];
            cout<<"Connection between "<<mta1<<" and "<<mta2<<endl;
            cout<<"     HELO "<<mta1<<"\n";
            cout<<"     250\n";
            cout<<"     MAIL FROM:<"<<s<<">\n";
            cout<<"     250\n";
            bool ok=false;
            for(int j=0; j<users.size(); j++)
            {
                cout<<"     RCPT TO:<"<<users[j]<<">\n";
                if(adder.count(users[j])){ok=true;cout<<"     250\n";}
                else cout<<"     550\n";
            }
            if(ok)
            {
                cout<<"     DATA\n";
                cout<<"     354\n";
                cout<<data;
                cout<<"     .\n";
                cout<<"     250\n";//
            }//
                cout<<"     QUIT\n";
                cout<<"     221\n";
        }
    }
    return 0;
}

Urban ElevationsUVA - 221离散化

在这里插入图片描述
在这里插入图片描述

题意:

给你每个长方体的
座标,wide,depth,height。
叫你求可以看到几个长方体(长方体之间没有重叠)

思路:

  1. 数据小,可以直接暴力。
  2. 由于座标是实数,所以要离散化。(x座标有无穷多个,离散后,把无穷变为有限)
  3. 先把输入按x座标降序排序(相等就按y降序排)。
  4. 之后查看第一个立方体就是左小角的那个(俯视图),那么正视图肯定可以看得到。先输出这个立方体的编号。
  5. 之后对于每个长方体都查看 **两个座标之间的中点**是否可以看到(且没有被挡住)。

AC

#include <iostream>
#include <algorithm>
#define For(i,x,y) for(register int i=(x); i<=(y); i++)
using namespace std;
const int maxn=1e3+10;
struct rect
{
    double x,y,w,d,h;
    int id;
    bool operator<(const rect &temp)const
    {return x<temp.x||(x==temp.x&&y<temp.y);}
}b[maxn];
int n,cnt=0;
double x[maxn*2];
bool online(int i, double pos)
{
    return b[i].x<=pos&&(b[i].x+b[i].w)>=pos;
}
bool check(int i, double pos)
{
    if(!online(i,pos))return false;
    For(k,1,n)
    {
        if(k==i)continue;
        if(b[k].y<=b[i].y&&b[k].h>=b[i].h&&check(k,pos))return false;
    }
    return true;
}
int main()
{
    int kase=0;
    while(cin>>n,n)
    {
        For(i,1,n)
        {
           cin>>b[i].x>>b[i].y>>b[i].w>>b[i].d>>b[i].h;
           x[cnt++]=b[i].x;
           x[cnt++]=b[i].x+b[i].w;
           b[i].id=i;
        }
        sort(x,x+cnt);
        sort(b+1,b+1+n);
        cnt=unique(x,x+cnt)-x;
        if(kase)cout<<endl;
        printf("For map #%d, the visible buildings are numbered as follows:\n%d",++kase,b[1].id);
        For(i,2,n)
        {
            For(j,0,cnt-2)
            {
                double mid=(x[j]+x[j+1])/2;
                if(check(i,mid))
                {
                    cout<<" "<<b[i].id;
                    break;
                }
            }
        }
        cout<<'\n';
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章