紫薯第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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章