sstream学习(~~留坑中。。。
~~EG题其实有涉及的)
模板 templete 体会。(留坑中。。。
)
eg题部分STL基础
Where is the Marble? UVA - 10474(sort && 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 - 101(vector,我的太丑了,就放紫薯的吧)
题意:
从左到右有 n 个木块,编号为0~ n - 1, 要求模拟一下4种操作(下面的a和b都是编号)
- move a onto b: 把 a 和 b 上方的木块全部归位,然后把 a 摞到 b 上面
- move a over b: 把 a 上方的木块全部归位,然后把 a 放在 b 所在木块堆的顶部
- pile a onto b: 把 b 上方的木块全部归位,然后把 a 及上面的木块 摞到 b 上面
- pile a over b: 把 a 及上面的木块 摞到 b 所在木块堆的顶部
思路:
由于每个堆的高度 不确定,所以适合用 vector 来保存
开一个vector【】,去模拟,就像stack(栈一样)。
反思:
- 本题有四个操作,如果完全独立地处理各命令,代码就会变得冗长而且容易出错。更好地办法是提取出指令间的共同点,编写函数,减少重复代码
- 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);
- ==vector也可以下标访问,==哎,用vector老是忘,直接去下标了。
- 比较字符可以在开头定义cosnt
const string t1="onto";
const string t2="move";
笔记:
- vector 之间可以直接赋值,或者作为函数的返回值
- 用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 - 10815(set)
题意:
有一个文本,要你找到所有的单词,之后按照字典序输出,不重复。(不区分大小写)
思路:
set 有序的集合,
- 由于可能带标点,所以把标点变成space,之后再用stringstream得到各个单词。
if(isalpha(s[i]))s[i]=tolower(s[i]);
//判断是否是字母,以及转换为小写。
else s[i]=' ';
stringstream ss(s);
while(ss>>buf)text.insert(buf);//在ss中插入
反思:
- isalpha() 判断是否是字母
- tolower(),转换为小写。
- stringstream ss(s) 的操作
stringstream ss(s);
while(ss>>buf)text.insert(buf);//在ss中插入
- 读到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 - 156(map)
题意:
输入一个单词文本,找出所有满足下面条件的单词。该单词不能通过字母重排,得到输入文本中的另一个单词。判断是否满足条件时,字母不分大小写,但在输入时应保留输入文中的大小写,按照字典序进行排列(所有大写字母在小写字母的前面)
思路:
- 本题说重排序,也就是说可以把每个单词内排好,之后放在map里记录。
eg cat 的 自己排序就是,act,后面如果出现act,那么cat肯定不是。 - 为了完成1,可以先把原文本存起来,之后对现有的文本进行标准化。
反思
- 字符串本身就可以 sort()
- 当时做的时候我还手写桶排,去排(哎哎哎啊)。
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)
题意:
有一个专门为了集合运算而设计的“集合栈”计算机。该机器有一个初始为空的栈,并且支持以下操作。
- PUHS:空集“{ }“入栈。
- DUP:把当前栈顶元素复制一份再入栈。
- UNION: 出栈两个集合,然后把两者的并集入栈。
- INTERSECT:出栈两个集合然后把两者的交集入栈。
- ADD: 出栈两个集合,然后把先出栈的集合加到后出栈的集合中,把结果入栈。
每次操作后,输出栈顶集合的元素个数。
反思&题解
本题的集合并不是简单的整数集合或者字符串集合,而是集合的集合。为了方便起见,此处为每一个不同的集合分配一个唯一的ID,则每个集合都可以表示成所包含元素的ID集合。(特殊地:空集的id为0).
#define ALL(x) x.begin(), x.end();
//先写两个宏,方便后面的操作。
#define INS(x) inserter(x,x.being())
//这里表示插入集合(inserter插入者)的宏、
- 对于集合交并可以调用:algorithm里的
set_union(ALL(x1), ALL(x2), INS(x))
set_intersection(ALL(x1), ALL(x2), INS(x)) - 可以#define SET set< int >(后面调用set时,比较方便。)
- 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(二维队列)
思路:
简单模拟。
- 建立一个团队队列,(只放团队的编号)
- 每个团队单独看成一个队列
- 在输入的时候,用map把每个队员的团队都标价一下。
收获:
- 队列可以开二维
- 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(优先队列)
思路:
- 可以找到规律,对于任意丑数x:2x,3x,5x也是丑数。
- 这就可以转换成队列的问题了。
- 对于入队的要标记这个丑数生成过
- 每次都拿最小的丑数去更新。
- 所以用优先队列去维护。
反思:
- 不开longlong见祖宗
- 对于转换成队列的问题了。 这个过程还不是很熟练。
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
之后
- col=(60-maxx)/(maxx+2)+1(向下取整)
- row=(n+col-1)/col(向上取整)
反思:
string 的 sort
- 对于string s【100】
不可以直接sort(s.begin(),s.end()) - 而要sort(s,s+n)
- 或者上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)
思路:
- 枚举列c1,c2.
- 之后扫一遍行,如果当前二元组之前出现过,就NO。(map存二元组的行号)
- 最后都没找到,就yes
反思:
map映射,编号
- 虽然二元组直接string也可以,但map中string的比较费时间(取决于string长度)。
- 所以可以先映射每个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,peter@neerc.ifmo.ru
How to win ACM ICPC,Michael,michael@neerc.ifmo.ru
Notes from ACM ICPC champion,Michael,michael@neerc.ifmo.ru
2 3
1,Peter,peter@neerc.ifmo.ru
2,Michael,michael@neerc.ifmo.ru
*/
PGA Tour Prize Money UVA - 207(大模拟毒瘤题目,字符的读入&&细节处理)
思路:
- 先把所有选手前两轮的得分进行排名。(题目保证一定有70人晋级)
- 接下来四轮总分再进行一次排序。
- 之后就是颁奖。
- 最后输出。
反思&&收获:
本题的输入一如既往要用getline
- 先吃回车:getchar。
- 之后读取一行:getline(cin,line)
- 由于名字是要读取21个字符,所以
play[i].name=line.substr(0,21);//输入名字
- 业余的判断
play[i].amateur=(find(line.begin(),line.end(),'*')!=line.end());
- 把字符string转换为int
stoi
- 把int转换为string
to_string(int)
输入X2
- 也可以把前20个给读取了fgets(char*,size,stdin)
- 之后用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将会通信。
输入:
- 先是每个MTA的用户列表。
- 对于每个发送请求(输入发送者和接收者列表),按顺序输出所有MTA之间的SMTP(简单邮件协议)交互。(详见题目)
- MTA1连接收件人的MTA2的顺序应该与输入“第一次出现的顺序”一致。
思路:
- 对于第一次输入每个MTA的用户列表
(用一个set< string > addr,是为了保存可能的用户的邮箱地址,方便后面输出时,查找是否有该用户。addr.count(adress))放在有序表里,我觉得而是为了查找,方便
- 对于输入,要根据邮箱地址,处理出收件人,(后面也有重复的操作),所以定义一个函数。
- map< string ,vector < string > >dest 定义,相当于把MTA1需要发送的用户地址放入。
之后看用户是否存在时,再与1中的set相比较,看是否有这个用户。
- 还要定义一个vector< string > mta为了存放MTA1要连接的其他MTA2.(这里是为了,题目的输出要求
与输入顺序一致
),再定义一个map< string > vis去记录,当前MTA,是否在vector里 - 输出时,遍历vector < > mta即可。对于每个MTA1所连接的MTA,要看dest【MTA】里存的用户地址了。之后输出时,要判断用户是否存在。
反思:
- map可以key为string,而value为一个数组。
- string可以不用初始化,直接加字符操作。也可以加换行。
- find函数,对于string 返回的好像可以是第几个。而set里,返回的是指针。
- 本题要小心空格的输出。
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。
叫你求可以看到几个长方体(长方体之间没有重叠)
思路:
- 数据小,可以直接暴力。
- 由于坐标是实数,所以要离散化。(x坐标有无穷多个,离散后,把无穷变为有限)
- 先把输入按x坐标降序排序(相等就按y降序排)。
- 之后查看第一个立方体就是左小角的那个(俯视图),那么正视图肯定可以看得到。先输出这个立方体的编号。
- 之后对于每个长方体都查看
**两个坐标之间的中点**
是否可以看到(且没有被挡住)。
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;
}