文章目录

  • 零碎知识点整理
  • 题目
    • 10474 - Where is the Marble?
    • 101 - The Blocks Problem
    • 10815 - Andy's First Dictionary
    • 156 - Ananagrams
    • 12096 The SetStack Computer
    • 540 - Team Queue
    • 136 - Ugly Numbers
    • 400 - Unix ls
    • 1592 - Database
    • 814 - The Letter Carrier's Rounds
    • 221 - Urban Elevations
    • 1593 - Alignment of Code
    • 1594 - Ducci Sequence
    • 10935 - Throwing cards away I
    • 10763 - Foreign Exchange
    • 10391 - Compound Words
    • 1595 - Symmetry
    • 12100 - Printer Queue
    • 1596 - Bug Hunt

相关博文: acm之旅–数据结构(STL总结)

零碎知识点整理

  • min,max,swap的头文件为algorithm(C++特有库)。
  • bool类型是C++特有的,C语言没有。
  • using namespace std的方法把std里的名字导入默认空间,可以使用cin来代替std::cin。但在工程中不推荐这样使用,在ACM竞赛中因为代码量小,所以无大碍。
  • C++中在函数的参数名之前加一个“&”符号,表示这个参数按照传引用的方式传递,即函数内改变参数值,也会修改函数的实参。
  • C++提供string类型来替代C语言中的字符数组。string类型有许多已经定义好的字符串操作函数,方便直接使用,只是比较慢。
  • stringstream的头文件为sstream,
while(getline(cin, line))//读取一行的字符串
{int sum = 0, x;stringstream ss(line);//创建字符串流while(ss >> x) sum += x;//按空格输出cout << sum << endl;
}
  • string中find()返回值是字母在母串中的位置(下标记录),如果没有找到,那么会返回一个特别的标记npos。(返回值可以看成是一个int型的数)。
position = s.find("jk");
if (position != s.npos)  //如果没找到,返回一个特别的标志c++中用npos表示,我这里npos取值是4294967295,{printf("position is : %d\n" ,position);}else{printf("Not found the flag\n");}

题目

10474 - Where is the Marble?

题目链接:10474 - Where is the Marble?

  • 题目大意:给出N个大理石的编号,排好序后,给出一个数x,回答是否存在编号为x的大理石,如果有则给出它是第几个,否则输出不存在信息。
  • 思路:裸题。sort+lower_bound。

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;const int MAX = 20000;
int T, N, Q, a[MAX], n;
int main()
{T = 1;while(scanf("%d%d", &N, &Q)!=EOF && (N+Q)){for(int i=0; i<N; i++)scanf("%d", &a[i]);sort(a, a+N);printf("CASE# %d:\n", T++);for(int i=0; i<Q; i++){scanf("%d", &n);int p = -1;p = lower_bound(a, a+N, n)-a;if(a[p]==n) printf("%d found at %d\n", n, p+1);else        printf("%d not found\n", n);/*for(int j=0; j<N; j++){if(a[j]==n){p = j+1;break;}}if(p==-1) printf("%d not found\n", n);else    printf("%d found at %d\n", n, p);*/}}return 0;
}
101 - The Blocks Problem

题目链接:101 - The Blocks Problem

  • 题目大意:
  • 思路:模拟题,但可以有技巧。仔细观察指令可知,move是将a上方的物块清除,onto是将b上方的物块清除。然后在将a及其上方的物块放置在b物块所在是列的上方。但主要是细节如何实现,书上的代码比较清晰,我定义了一个结构体Node,bot表示物块所在底层块编号,idx表示该物块所在列的数组中的下标,id表示自己的编号。总之,通过改变bot和idx来改变物块的位置,具体见代码。同时还有注意非法指令。
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;const int MAX = 30;
vector<int> upp[MAX];
char order1[10], order2[10];
int a, b, n;
struct Node
{int bot, idx, id;//所在列的底层块编号,所在列的自己的下标,自己的编号
}B[MAX];int main()
{scanf("%d", &n);for(int i=0; i<n; i++){B[i].bot = i, B[i].idx = -1, B[i].id = i;}while(scanf("%s", order1)!=EOF && order1[0]!='q'){scanf("%d%s%d", &a, order2, &b);int sta = B[a].idx, ida = B[a].bot;int stb = B[b].idx, idb = B[b].bot;//当在同一列时是非法指令,忽略if(ida==idb) continue;//move指令将a物体上方所有的物块清空if(order1[0]=='m'){for(int i=upp[ida].size()-1; i>sta; i--){int v = upp[ida][i];B[v].bot = B[v].id;B[v].idx = -1;upp[ida].pop_back();}}//onto命令,将b物块上方所有的物体清空if(order2[1]=='n'){for(int i=upp[idb].size()-1; i>stb; i--){int v = upp[idb][i];B[v].bot = B[v].id;B[v].idx = -1;upp[idb].pop_back();}}if(sta==-1)//当是最底层的那个物块,a入b列{B[a].bot = idb;B[a].idx = upp[idb].size();sta = 0;upp[idb].push_back(B[a].id);}//a及其上方的物块放入b列中for(int i=sta; i<upp[ida].size(); i++){int v = upp[ida][i];B[v].bot = idb;B[v].idx = upp[idb].size();upp[idb].push_back(B[v].id);}for(int i=upp[ida].size()-1; i>=sta; i--)//清空a及其上方的物块upp[ida].pop_back();}//打印输出for(int i=0; i<n; i++){printf("%d:", i);if(B[i].bot!=i){printf("\n");continue;}printf(" %d", i);for(int j=0; j<upp[i].size(); j++)printf("% d", upp[i][j]);printf("\n");}return 0;
}
10815 - Andy’s First Dictionary

题目链接:10815 - Andy’s First Dictionary

  • 题目大意:输入一个文本,找出文本中所有不同的单词,按字典序从大到小排列,单词不区分大小写,输出为小写。
  • 思路:简答题。使用set存储提取出的所有单词,自动按字典序排列。那么就需要处理输入的文本,我是按字符输入,前一个是字母,后一个遇到非字母的就认为提取出了一个单词,插入集合中,不要忘了在文本输入结束后在处理最后一个单词。

代码:

#include <iostream>
#include <cstdio>
#include <set>
#include <cctype>
#include <cstring>
using namespace std;char ch;
string s;
set<string> Set;
int main()
{s = "";int flag = 0;//用来标记上一个是不是字母while((ch=getchar())!=EOF){if(isalpha(ch)){s += tolower(ch);flag = 1;}else if(flag)//前一个是字母{Set.insert(s);s = "";flag = 0;}}if(flag) Set.insert(s);set<string>::iterator it;for(it=Set.begin(); it!=Set.end(); it++){cout << *it << endl;}return 0;
}
156 - Ananagrams

题目链接:156 - Ananagrams

  • 题目大意:输入一些单词,找出所有满足下列条件的单词:该单词不能通过字母重排,得到输入文本中的另外一个单词。在判断是否满足条件时,字母不分大小写,但在输出时应保留输入中的大小写,按字典序进行排列(所有大写字母在所有小写字母的前面)。
  • 思路:有一定的技巧。重点是将每一个单词标“标准化”,即全部转换为小写字母后在进行排序,可以用来查重。我的思想是用两个set,一个存储只出现过一次的标准化字符串,另一个存储出现过多次的标准化字符串。然后在用一个map来将标准化字符与原始字符串对应起来,通过遍历第一个set就可以获得所有的结果,然后排序即可。这个是书上的思路:156 - Ananagrams

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <set>
#include <map>
#include <vector>
using namespace std;string a, b;
set<string>Set1, Set2;//Set1存储出现一次的标准字符串,Set2存储出现了多次的标准字符串
map<string, string>m;//标准字符串与原始字符串的映射
vector<string> ans;//存储结果int main()
{while(cin >> a){int len = a.size();if(a[0]=='#' && len==1) break;//转换为标准字符串b = a;for(int i=0; i<len; i++)b[i] = tolower(b[i]);sort(b.begin(), b.end());if(Set2.count(b)) continue;if(Set1.count(b)){Set1.erase(b);Set2.insert(b);continue;}m[b] = a;Set1.insert(b);}//获取对应的原始字符串set<string>::iterator it;for(it=Set1.begin(); it!=Set1.end(); it++){string c = m[*it];ans.push_back(c);}//按字典序排序sort(ans.begin(), ans.end());for(int i=0; i<ans.size(); i++)cout << ans[i] << endl;return 0;
}
12096 The SetStack Computer

题目链接:12096 The SetStack Computer

  • 题目大意:PUSH:向栈中放一个空集合。
    DUP:复制栈顶集合。
    UNION:取栈顶的两个集合,取并集后放回。
    INTERSECT:取栈顶的两个集合,取交集后放回。
    ADD:取栈顶两个集合,将第一个集合作为元素放到第二个集合中,并将第二个集合放回栈。
    每次操作后输出栈顶集合中元素的个数。
  • 思路:比较好的题目。通过一个map将不同集合映射成为不同的数字,该数字表示存储结合数组的下标,通过该数字就可以找到该集合。而栈内只需要存储数字即可。同时注意STL中有关于set集合并集和交集的操作set_union和set_intersection。还有空集合的声明set<int>()

代码:

#include<iostream>
#include<string>
#include<set>
#include<map>
#include<stack>
#include<vector>
#include<algorithm>
using namespace std;#define ALL(x) x.begin(),x.end()
#define INS(x) inserter(x,x.begin())typedef set<int> Set;
map<Set,int> IDcache; // 把集合映射成ID(vector数组下标)
vector<Set> Setcache; // 根据ID下标取集合// 查找给定集合x的ID。如果找不到,分配一个新ID
int ID (Set x) {if (IDcache.count(x)) return IDcache[x];Setcache.push_back(x); // 添加新集合return IDcache[x] = Setcache.size() - 1;
}int main () {int T;cin >> T;while(T--) {stack<int> s; // 题目中的栈int n;cin >> n;for(int i = 0; i < n; i++) {string op;cin >> op;if (op[0] == 'P') s.push(ID(Set()));else if (op[0] == 'D') s.push(s.top());else {Set x1 = Setcache[s.top()]; s.pop();Set x2 = Setcache[s.top()]; s.pop();Set x;if (op[0] == 'U') set_union (ALL(x1), ALL(x2), INS(x));if (op[0] == 'I') set_intersection (ALL(x1), ALL(x2), INS(x));if (op[0] == 'A') { x = x2; x.insert(ID(x1)); }s.push(ID(x));}cout << Setcache[s.top()].size() << endl;}cout << "***" << endl;}return 0;
}
540 - Team Queue

题目链接:540 - Team Queue

  • 题目大意:有t个团队的人正在排一个长队。每次新来一个人时,如果他有队友在排队,那么这个新人会插队到最后一个队友的身后。如果没有任何一个队友排队,则他会排到长队的队尾。输入每个团队中所有队员的编号,要求支持如下3种指令(前两种指令可以穿插进行)。

ENQUEUEx:编号为x的人进入长队。
DEQUEUE:长队的队首出队。
STOP:停止模拟。

  • 思路:这道题使用队列比较巧妙。采用了两个队列,一个存储团队的编号顺序,一个是队列数组,存储不同团队内的编号。出队列是先取团队队列的首元素,然后知道是哪个团队在前面,在取该团队的首元素出队列。入队列是,直接将该元素入对应团队的队列即可。

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <map>
#include <queue>
using namespace std;const int MAX = 1050;
int Case = 1, n, t, T;
char op[10];int main()
{while(scanf("%d", &T) && T){//在里面命令省去了之后的清空操作map<int, int> m;queue<int> q, q1[MAX];//q是团队编号的队列,q1[i]是编号为i的团队的队列printf("Scenario #%d\n", Case++);for(int i=1; i<=T; i++){scanf("%d", &n);for(int j=0; j<n; j++){scanf("%d", &t);m[t] = i;//对应编号}}while(scanf("%s", op) && op[0]!='S'){if(op[0]=='E'){scanf("%d", &t);int id = m[t];//获得对应团队的编号if(q1[id].empty()) q.push(id);//团队队列维护q1[id].push(t);//对应团队的队列更新}else if(op[0]=='D'){int id = q.front();//获得出队列的团队的编号printf("%d\n", q1[id].front());q1[id].pop();if(q1[id].empty()) q.pop();//维护团队队列}}printf("\n");}return 0;
}
136 - Ugly Numbers

题目链接:136 - Ugly Numbers

  • 题目大意:定义一个丑数,其不能被2、3、5以外的其他素数整除。把丑数从小到大排列起来,求第1500个丑数。
  • 思路:采用递推的方式。首先1是丑数,然后2、3、5也是,所以如果x是丑数,那么2x、3x和5x也是。这样既可以使用优先队列存储得到的丑数,然后每一次取出最小的计算其2倍、3倍、5倍新的丑数入队列,同时可以使用集合来辅助判断该丑数是不是已经产生过。

代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <set>
using namespace std;const int MAX = 1500;
typedef long long LL;
set<LL> S;
priority_queue<LL, vector<LL>, greater<LL> >pq;
LL a, b, c, t;
int main()
{int cnt = 0;//初始化pq.push(1);S.insert(1);while(cnt<MAX){t = pq.top(); pq.pop();cnt++;a = t*2, b = t*3, c = t*5;if(!S.count(a)) pq.push(a), S.insert(a);if(!S.count(b)) pq.push(b), S.insert(b);if(!S.count(c)) pq.push(c), S.insert(c);}printf("The 1500'th ugly number is %lld.\n", t);return 0;
}
400 - Unix ls

题目链接:400 - Unix ls

  • 题目大意:给出n个文件名,让你排完序后,按列优先输出,且要保证行最少,同时行最多输出60个字符,每一列是最长文件名的宽度,中间相隔2个空格。
  • 思路:主要是按照要求输出的难点和理解清楚题目意思。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;string s[101], G[101][60];
int n;int main()
{while(cin >> n){int Max = 0;for(int i=0; i<n; i++){cin >> s[i];if(Max<s[i].size()) Max = s[i].size();}printf("------------------------------------------------------------\n");sort(s, s+n);int col = (60+2)/(Max+2);//列数int R = (n+col-1)/col, k = 0, rc;for(int r=0; r<R; r++){for(int c=0; c<col; c++){if(c) printf("  ");int idx = c*R+r;//数组的下标if(idx<n)printf("%*s", -Max, s[idx].c_str());}printf("\n");}}return 0;
}
1592 - Database

题目链接:1592 - Database
参考博文:UVa_1592 - Database

  • 题目大意:给一个数据库,查找是否存在(r1,c1)=(r2,c1) && (r1,c2)=(r2,c2),即:不同的二行,对应二列字符串相同。
  • 思路:先将各列字符串转换为对应的数字编号,然后存入数组,转换为二维数组,然后枚举二维数组的两个列(每列对应的值作为map的键),然后映射其对应的行数,找到键值相等的就可以输出NO,及其存储的相关值,否则输出YES。

代码:

#include<iostream>
#include<cstdio>
#include<map>
#include<string>
#include<vector>
using namespace std;const int ROW = 10000 + 10;
int n,m;
map<string, int> IDcache;//将每一个字符串转化为一个数字
vector<string> Strcache;//辅助转化数字
vector<int> Text[ROW]; //保存处理后的文本,每个字符串都替换成一个编号
struct node
{int x,y;node(int x, int y):x(x),y(y) { }bool operator < (const node& r) const { return x<r.x || x==r.x&&y<r.y; }
};
map<node,int> data;int ID_alloc(string str)
{if(IDcache.count(str)) return IDcache[str];Strcache.push_back(str);return IDcache[str] = Strcache.size()-1;
}void read()
{string str;char ch = getchar();for(int i=0;i<n;i++){for(;;){ch = getchar();if(ch=='\n'||ch=='\r') {if(!str.empty()) Text[i].push_back(ID_alloc(str));//转化后的数字进数组str.clear();  break;}if(ch!=',') str += ch;else {//cout << 1 << endl;Text[i].push_back(ID_alloc(str)); str.clear();}}}
}void solve()
{int x,y,c1,c2;for(c1=0;c1<m;c1++){for(c2=c1+1;c2<m;c2++){data.clear();for(int r=0;r<n;r++){x = Text[r][c1]; y = Text[r][c2];//枚举两列的数字node p(x,y);if(!data.count(p)) data[p] = r;else{//相同的数字在两列分别重复出现cout<<"NO"<<endl;cout<<data[p]+1<<" "<<r+1<<endl<<c1+1<<" "<<c2+1<<endl;return;}}}}cout<<"YES"<<endl;
}int main()
{//freopen("1592.txt","r",stdin);while(cin>>n>>m){read();solve();for(int i=0;i<n;i++) Text[i].clear();IDcache.clear(); Strcache.clear();}return 0;
}
814 - The Letter Carrier’s Rounds

题目链接:814 - The Letter Carrier’s Rounds

  • 题目大意:一个邮件传输的模拟题。
  • 思路:一个题意比较复杂的模拟题。注意set,map的使用,细节的分析,收件人可能有重的需要去除。

代码:

#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('@');user=s.substr(0,k);mta=s.substr(k+1);
}int main(){int k;string s,t,user1,mta1,user2,mta2;set<string> addr;//输入所有MTA,转化为地址列表while(cin>>s && s!="*"){cin>>s>>k;while(k--){ cin>>t; addr.insert(t+"@"+s);}//拼接为地址}while(cin>>s && s!="*"){parse_address(s,user1,mta1);//处理发件人地址vector<string> mta;//所有需要连接的mta,按照输入顺序map<string, vector<string> > dest;//每个MTA需要发送的用户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);//把'*'这一行的回车吃掉//输入文件正文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 i=0;i<users.size();i++){cout<<"     RCPT TO:<"<<users[i]<<">\n";if(addr.count(users[i])){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;
}
221 - Urban Elevations

题目链接:221 - Urban Elevations
参考博文:UVa 221 Urban Elevations 城市正视图 离散化初步 无限化有限

  • 题目大意:给出城市中建筑物的x, y 坐标的最小值:x,y , 再给出其以左下角为坐标原点的关于x轴、y轴上的长度 w, 和 d,最后给出建筑物的高度 h,将建筑物的正视图中,能够看到的建筑物的id打印出来:要求先打印x小的,当x相同时,打印y小的。为了简化,假定建筑物都是长方体。同时,每个输出之间要用一个空行隔开 。
  • 思路:连续区域离散化,技巧。首先从正视图入手,正视图中存储在多个区域,单个区域仅由单个建筑物构成,所以需要先找到每一个建筑物可以在哪些区域中出现,然后在这些建筑物中筛选出真正可以显现的建筑物。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;const int maxn = 105;
struct Node
{int id;double x, y, w, d, h;bool operator < (const Node &A) const{if(x==A.x)return y<A.y;elsereturn x<A.x;}
};
Node b[maxn];
int n;
double x[maxn*2];//判断建筑物i是否经过mx处
bool cover(int i, double mx)
{if(b[i].x <= mx && b[i].x+b[i].w>=mx)return 1;elsereturn 0;
}
//判断建筑物i是否在mx处可见
bool visible(int i, double mx)
{if(!cover(i, mx)) return 0;//经过mx处for(int k=0; k<n; k++){if(k==i) continue;if(cover(k, mx) && b[k].y<b[i].y && b[k].h>=b[i].h)//保证其他建筑物不遮挡该建筑物return 0;}return 1;
}
int main()
{int kase = 0;while(scanf("%d", &n)==1 && n){for(int i=0; i<n; i++){scanf("%lf%lf%lf%lf%lf", &b[i].x, &b[i].y, &b[i].w, &b[i].d, &b[i].h);x[i*2] = b[i].x, x[i*2+1] = b[i].x+b[i].w;//存储区域边界b[i].id = i+1;}sort(b, b+n);sort(x, x+n*2);int m = unique(x, x+2*n)-x;//筛选去重,得到去重后的大小if(kase) printf("\n");printf("For map #%d, the visible buildings are numbered as follows:\n", ++kase);int cnt = 0;for(int i=0; i<n; i++){int flag = 0;for(int j=0; j<m-1; j++){if(visible(i, (x[j]+x[j+1])/2))//判断该区域中建筑物i是否可见{flag = 1;break;}}if(flag){if(cnt) printf(" ");printf("%d", b[i].id);cnt++;}}printf("\n");}return 0;
}
1593 - Alignment of Code

题目链接:1593 - Alignment of Code
题目大意:输入若干行字符串,每一个单词之间有多个空格,每一个单词不超过80个字符,每行不超过180个字符,一共最多1000多行,输出各列单词的左边界对齐且尽量靠左,单词之间至少空一格。

  • 思路:主要考察了stringstream、数组和printf的使用,主要要注意输出的每一行末尾都不要有空格。需要记录每一列的最大长度,已经每一行有多少个单词。

代码:

#include <iostream>
#include <cstdio>
#include <sstream>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;const int maxc = 200;
const int maxr = 1500;
int len[maxc], col[maxr];//len记录每一列的最大长度,col记录每一行的单词个数
string words[maxr][maxc];//记录每一个单词
string s, str;int main()
{int k = 0;memset(len, 0, sizeof(len));while(getline(cin, s)){stringstream ss(s);int cnt = 0;while(ss >> str){int t = str.size();len[cnt] = max(len[cnt], t);//更新每一列最大长度words[k][cnt++] = str;}col[k++] = cnt;}for(int i=0; i<k; i++){for(int j=0; j<col[i]; j++){if(j) printf(" ");if(j==col[i]-1) break;//着重注意,每一行最后一个单词要特殊输出printf("%*s", -len[j], words[i][j].c_str());}printf("%s\n", words[i][col[i]-1].c_str());//保证末尾无空格}return 0;
}
1594 - Ducci Sequence

题目链接:1594 - Ducci Sequence

  • 题目大意:对于一个n元组(a1,a2,…),一次变换后变成(|a1-a2|,|a2-a3|,…|an-a1|)
    问1000次变换以内是否存在循环,或各个元素更新为0。
  • 思路:裸题,简单模拟。注意函数传数组引用使用*。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;const int MAX = 30;
int T, n;
int a[MAX], b[MAX];int Sum(int a[], int n)
{int sum = 0;for(int i=0; i<n; i++)sum += a[i];return sum;
}
void Ducci(int *a, int *b, int n)//数组传引用
{int t = abs(a[0]-a[n-1]);b[n-1] = t;for(int i=0; i<n-1; i++){b[i] = abs(a[i]-a[i+1]);}memcpy(a, b, sizeof(int)*n);
}
int main()
{scanf("%d", &T);while(T--){scanf("%d", &n);for(int i=0; i<n; i++){scanf("%d", &a[i]);}int flag = 0;for(int i=0; i<1001; i++){if(!Sum(a, n))//判断是各个元素均为0{flag = 1;break;}Ducci(a, b, n);//更新操作}if(flag)printf("ZERO\n");elseprintf("LOOP\n");}return 0;
}
10935 - Throwing cards away I

题目链接:10935 - Throwing cards away I

  • 题目大意:有n张牌,进行一下操作:丢弃第一张牌,然后将之后的第一张牌放在最后面,直到只剩下最后一张牌。问牌丢弃的序号序列和最后一张牌的编号。
  • 思路:简单模拟题。队列模拟操作即可。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;queue<int> q;
void Init(int n)
{while(!q.empty()) q.pop();for(int i=1; i<=n; i++){q.push(i);}
}
int main()
{int n;while(scanf("%d", &n) && n!=0){vector<int> v;Init(n);//初始化牌//模拟操作while(q.size()>1){v.push_back(q.front());q.pop();int t = q.front();q.pop();q.push(t);}int r = q.front();printf("Discarded cards:");for(int i=0; i<v.size(); i++){if(i) printf(",");printf(" %d", v[i]);}printf("\n");printf("Remaining card: %d\n", r);}return 0;
}
10763 - Foreign Exchange

题目链接:10763 - Foreign Exchange

  • 题目大意:给出多对数字a和b,表示一名学生想从a学校交换到b学校,但如果想成功,他需要找到另一个从b学校交换到a学校的学生,问你是否所有的学生均可以成功交换。
  • 思路:简单题,STL的使用。使用set存储从a到b的学生个数(同时存储所有的a和b的组合),然后遍历set判断从a到b的学生人数是否等于从b到a的学生个数。

代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <map>
#include <set>
using namespace std;const int MAX = 500005;
int a, b;
struct Node
{int a, b;Node(int a=-1, int b=-1):a(a), b(b){}bool operator < (const Node &A) const{//大小关系一定要写全if(a!=A.a)return a<A.a;elsereturn b<A.b;}
};int main()
{int n;while(scanf("%d", &n) && n){map<Node, int>m;set<Node>s;for(int i=0; i<n; i++){scanf("%d%d", &a, &b);if(m.count(Node(a,b))){m[Node(a,b)] = m[Node(a,b)]+1;}else{m[Node(a,b)] = 1;}if(!s.count(Node(b, a)))s.insert(Node(a,b));//a和b组合}int flag = 1;set<Node>::iterator it;for(it=s.begin(); it!=s.end(); it++){int ai = (*it).a, bi = (*it).b;if(m[*it]!=m[Node(bi, ai)])//判断是否能够交换{flag = 0;break;}}if(flag) printf("YES\n");else     printf("NO\n");}return 0;
}
10391 - Compound Words

题目链接:10391 - Compound Words

  • 题目大意:给出一些单词,问在这些单词中是否存在一些单词是由其它两个单词组成的。
  • 思路:技巧题。先将所有单词存入集合,然后遍历取出每一个单词,枚举切分,判断切分出的两个单词是否在集合中。

代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <set>
using namespace std;set<string> s, ans;
string a;int main()
{while(cin >> a) s.insert(a);set<string>::iterator it;//枚举切分for(it=s.begin(); it!=s.end(); it++){string b = *it, b1, b2;for(int i=1; i<b.size(); i++){b1 = "", b2 = "";for(int j=0; j<i; j++) b1 += b[j];for(int j=i; j<b.size(); j++) b2 += b[j];if(s.count(b1) && s.count(b2)) ans.insert(b);//存储符合清空的单词}}for(it=ans.begin(); it!=ans.end(); it++){cout << *it << endl;}return 0;
}
1595 - Symmetry

题目链接:1595 - Symmetry

  • 题目大意:给出平面上一些点,问是否可以在平面上找到一个竖线使得所有点关于这个竖线左右对称。
  • 思路:首先将所有点按x轴从小到大排序。然后得到中间线(中间点的x坐标或中间两点x坐标的均值)。遍历数组的前半部分,找到其对称点,判断其对称点是否在在点的集合中。

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <set>
using namespace std;const int MAX = 1005;
struct Node
{double x, y;Node(double x=-1, double y=-1):x(x), y(y){}bool operator < (const Node &A) const{if(x==A.x)return y<A.y;elsereturn x<A.x;}
};
Node a[MAX];
set<Node> b;int main()
{int n, T;scanf("%d", &T);while(T--){scanf("%d", &n);for(int i=0; i<n; i++){scanf("%lf%lf", &a[i].x, &a[i].y);b.insert(Node(a[i].x, a[i].y));}sort(a, a+n);double mid;//竖线的位置int idx;//获取竖线的位置if(n%2){mid = a[n/2].x;idx = n/2;}else{mid = (a[n/2-1].x+a[n/2].x)/2.0;idx = n/2;}//遍历得对称点int flag = 1;for(int i=0; i<idx; i++){double x = 2*mid-a[i].x, y = a[i].y;//对称点if(!b.count(Node(x, y))){flag = 0;break;}}if(flag) printf("YES\n");else     printf("NO\n");}return 0;
}
12100 - Printer Queue

题目链接:12100 - Printer Queue

  • 题目大意:一个由优先级的队列中取元素,每一次只能去优先级最高的,在其之前的要加入对列末尾,问初始给定的那个元素在第几次取出来。
  • 思路:简单题。只不过会使用的结构比较多一些。我这里使用优先队列来得到每一次需要取出的优先级大小,还有普通的队列来模拟取元素,并且使用结构体来标记选中的元素。

代码:

#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;struct Node
{int v, f;//v是优先级值,f标记被选中的元素Node(int v=-1, int f=-1):v(v), f(f){}
};
queue<Node> q;
priority_queue<int> q1;//默认是大顶堆int main()
{int T, n, m, t;scanf("%d", &T);while(T--){//注意初始化清空队列while(!q.empty()) q.pop();while(!q1.empty()) q1.pop();scanf("%d%d", &n, &m);//输入并近队列for(int i=0; i<n; i++){scanf("%d", &t);if(i==m){q.push(Node(t, 1));q1.push(t);}else{q.push(Node(t, 0));q1.push(t);}}int cnt = 0, f = 0;while(!f)//判断是否是选中的元素{int next = q1.top();//下一个应该被取出的优先级Node u = q.front();while(u.v<next){q.pop();q.push(u);u = q.front();}f = u.f;q.pop();q1.pop();cnt++;//次数加一}printf("%d\n", cnt);}return 0;
}
1596 - Bug Hunt

题目链接:1596 - Bug Hunt
参考博文:LLGEMINI

  • 题目大意:具体参考书目。
  • 思路:模拟题,看似不复杂但是做了一下午也没有调通,伤心,参考别人代码。

算法竞赛入门经典(第2版)—第五章(C++与STL入门)相关推荐

  1. 第五章 C++与STL入门 例题

    提交地址: 算法竞赛入门经典(第二版)-刘汝佳-第五章 C++与STL 例题 中文题目地址:算法竞赛入门经典(第二版)-刘汝佳-第五章 C++与STL 例题与习题 5.1 从C到C++ 5.2 STL ...

  2. 算法竞赛入门经典(第二版)第二章教材代码

    //程序 2-2 7744问题(1) #include <stdio.h> #include <math.h> int main() {for(int a=1; a<=9 ...

  3. 《算法竞赛入门经典(第2版)》——学习记录

    前言:   这里主要记录本人在学习紫书过程中充分理解过的题目的AC代码,便于以后回顾时查找代码和思路,毕竟看别人的真的有点难懂.此外,本书甚至是本书之外的相关知识学习也可能在此留下记录.   作为一只 ...

  4. 算法竞赛入门经典(第二版)第三章习题

    声明:作者水平有限,只是会基础C语言的小菜,C++还未入门.作者仅根据算法竞赛入门经典(第二版)书上第三章习题所述题意而编写,并未严格按照原题的输入输出编写,代码仅经过个人测试(OJ网站太慢了).代码 ...

  5. 刘汝佳《算法竞赛入门经典(第二版)》习题(三)

    刘汝佳<算法竞赛入门经典(第二版)>第三章习题(一) 习题3-1 得分(ACM/ICPC Seoul 2005,UVa1585) 给出一个由O和X组成的串(长度为1~80),统计得分.每个 ...

  6. 刘汝佳《算法竞赛入门经典(第二版)》习题(六)

    刘汝佳<算法竞赛入门经典(第二版)>第四章习题(4-1~4-3) 习题4-1 象棋(Xiangai,ACM/ICPC Fuzhou 2011,UVa1589) 考虑一个象棋残局,其中红方有 ...

  7. 刘汝佳《算法竞赛入门经典(第二版)》习题(二)

    刘汝佳<算法竞赛入门经典(第二版)>第二章习题 目录 刘汝佳<算法竞赛入门经典(第二版)>第二章习题 习题2-1 水仙花数 习题2-2 韩信点兵 习题2-3 倒三角形 习题2- ...

  8. 算法竞赛入门经典 第2版

    算法竞赛入门经典 包括算法竞赛入门经典训练指南.算法竞赛入门经典各章习题答案.算法竞赛入门经典(第二版) 链接:https://pan.baidu.com/s/1O-bGyhdCqYtRvSBpn7J ...

  9. 《算法竞赛入门经典(第2版)》

    <算法竞赛入门经典(第2版)> 基本信息 作者: 刘汝佳 丛书名: 算法艺术与信息学竞赛 出版社:清华大学出版社 ISBN:9787302356288 上架时间:2014-6-5 出版日期 ...

  10. JavaScript入门经典(第4版)

    循序渐进精细讲解所有JavaScript知识点 指导您构建建出神入化的完美Web应用程序 JavaScript入门经典(第4版) 基本信息 原书名: Beginning JavaScript 原出版社 ...

最新文章

  1. 获取邮箱通讯录,msn好友列表的C#源码
  2. 线性回归损失函数为什么要用平方形式
  3. 《SolidWorks 2016中文版机械设计从入门到精通》——1.10 范例
  4. gsonformat插件_收藏非常有用的IDEA插件,没用过这些IDEA插件?怪不得写代码头疼
  5. Vue项目代码改进(六)—— vue的mixins的使用
  6. python计算分段函数_Python练习题2.2计算分段函数
  7. javascript Event监听
  8. 虚拟环境下配置拨号接入的×××
  9. 如何画圆柱_木饰面、金属包立柱,该如何设计?
  10. 金蝶专业版服务器提示系统错误,金蝶专业版连接云服务器异常
  11. Android文件或文件夹压缩成.zip格式的压缩包
  12. linux的应用界面设计,技术|Xperience UI 设计理念:优雅的 Linux 桌面设计欣赏
  13. 学计算机的一定是好男人,心理学:只要满足3个条件,好男人也会学“坏”
  14. Liquibase常用操作
  15. uoj 246. 【UER #7】套路
  16. 分类之混淆矩阵(Confusion Matrix)
  17. 【unity shader/风格化水表面渲染/基础笔记】urp代码版05-焦散模拟
  18. 蓝牙卡复制html,车库蓝牙卡能复制吗
  19. Python--画图时希腊字母的显示
  20. CT影像与超声影像的融合(fusion)的原理是什么

热门文章

  1. 「操作系统」深入理解死锁(什么是死锁?死锁形成条件?如何避免死锁?如何排查死锁?)
  2. CentOS8—ssh免密登录
  3. Spark 持久化(cache和persist的区别)
  4. 【云服务器搭建游戏私服】全流程
  5. Apache 安装详解
  6. C语言练习1-判断四根木棍是否可以摆成三角形
  7. OpenMP: OpenMP嵌套并行
  8. Graphql是什么
  9. Android Studio模拟器报错:Could not initialize DirectSoundCapture
  10. python 键盘记录_记录键盘敲击次数 python实现