算法竞赛入门经典(第2版)-刘汝佳-第五章解题源码(C++语言)(部分)

来源:互联网 发布:企业网络危机公关方案 编辑:程序博客网 时间:2024/06/06 02:58

例题5-1

本题思路:书中p108有详细思路。本题我用了vector进行排序和寻找相等元素。

#include<iostream>#include<algorithm>#include<vector>using namespace std;int main(){//freopen("datain.txt","r",stdin);//freopen("dataout.txt","w",stdout);int n,q,rnd=1;while(cin>>n>>q&&n){cout<<"CASE# "<<rnd++<<":"<<endl;vector<int> marble;while(n--){int tmp;cin>>tmp;marble.push_back(tmp);}sort(marble.begin(),marble.end());while(q--){int tmp,index;cin>>tmp;index=lower_bound(marble.begin(),marble.end(),tmp)-marble.begin();if(marble[index]==tmp)cout<<tmp<<" found at "<<index+1<<endl;elsecout<<tmp<<" not found"<<endl;}}return 0 ;} 

例题5-2

本题主要学会通过resize的方法来进行元素的快速删除,并且学习连续cin string的方法来判断是否结束程序。

#include<iostream>#include<string>#include<vector>using namespace std;const int maxn=30;int n;vector<int> pile[maxn];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 b=pile[p][i];pile[b].push_back(b);}pile[p].resize(h+1);//没有去删除元素,改变大小来进行删除 }void pile_onto(int p,int h,int p2){for(int i=h;i<pile[p].size();i++){pile[p2].push_back(pile[p][i]);}pile[p].resize(h);}void print(){for(int i=0;i<n;i++){cout<<i<<":";for(int j=0;j<pile[i].size();j++){cout<<" "<<pile[i][j];} cout<<endl;}}int main(){//freopen("datain.txt","r",stdin);//freopen("dataout.txt","w",stdout);int a,b;cin>>n;string s1,s2;for(int i=0;i<n;i++){pile[i].push_back(i);}while(cin>>s1>>a>>s2>>b)//接收输入的技巧要掌握 {int pa,pb,ha,hb;find_block(a,pa,ha);find_block(b,pb,hb);if(pa==pb) continue;if(s2=="onto") clear_above(pb,hb);if(s1=="move") clear_above(pa,ha);pile_onto(pa,ha,pb); }print();return 0;} 

例题5-3

cin string 是以空格为界的,本题通过stringstream来将有空格的string进行了分割。实际上,先将string转换为stringstream,输入到string中,在输入的时,本身string遇到空格就会停止。其次是对遍历set进行了了解。

#include<iostream>#include<set>#include<string>#include<sstream>using namespace std;set<string> dict;int main(){//freopen("datain.txt","r",stdin);//freopen("dataout.txt","w",stdout);string s,buf;while(cin>>s){for(int i=0;i<s.length();i++)//字符串通过length方法直接获得长度 {if(isalpha(s[i])){s[i]=tolower(s[i]);} else{s[i]=' ';}}stringstream ss(s);//将s转化为一个字符流。while(ss>>buf)//通过字符串流,将字符串中根据空格进行了分离。 {dict.insert(buf);} }for(set<string>::iterator it =dict.begin();it!=dict.end();++it)cout<<*it<<endl;return 0;} 

例题5-4

本题目主要对单词进行排序,然后来判断是否为反片语。

#include<iostream>#include<string>#include<cctype>#include<vector>#include<map>#include<algorithm>using namespace std;map<string,int> cnt;vector<string> words;string repr(const string &s){string ans=s;for(int i=0;i<ans.length();i++ ){ans[i] = tolower(ans[i]);}sort(ans.begin(),ans.end());return ans;}int main(){int n=0;string s;while(cin>>s){if(s[0]=='#') break;words.push_back(s);string r = repr(s);if(!cnt.count(r)){cnt[r]=0; }cnt[r]++;}vector<string> ans;for(int i=0;i<words.size();i++){if(cnt[repr(words[i])]==1)ans.push_back(words[i]);}sort(ans.begin(),ans.end());for(int i=0;i<ans.size();i++){cout<<ans[i]<<endl;}return 0;}

例题5-5

本题的重要思想是将索引和实体分离的策略,有助于操作,而集合的操作。使用了set_union函数,具体用法为

set_union(A.begin(),A.end(),B.begin(),B.end(),inserter(C1 , C1.begin() ) );前四个参数依次是第一的集合的头尾,第二个集合的头尾。第五个参数的意思是将集合A、B取合集后的结果存入集合C中。通过定义宏,进一步减少代码的重复性。另外注意set<int> ()为空集。本题主要是拓宽了处理思路。有助于学习。

#include<iostream>#include<set>#include<vector>#include<map>#include<stack> #include<string>#include <algorithm>  #define ALL(x) x.begin(),x.end()#define INS(x) inserter(x,x.begin())using namespace std;typedef set<int> Set;map<Set,int> IDcache;vector<Set> Setcache; int ID (Set x){if(IDcache.count(x)) {  return IDcache[x];} Setcache.push_back(x);return IDcache[x] = Setcache.size()-1;}int main(){//freopen("datain.txt","r",stdin);//freopen("dataout.txt","w",stdout);int rnd;cin>>rnd;while(rnd--){stack<int> s;int n;cin>>n;while(n--){string op;cin>>op;if(op[0]=='P') {s.push(ID(Set()));//s中存储的是集合的索引 } else if(op[0]=='D') {s.push(s.top());}else{Set x1 = Setcache[s.top()];//弹出索引,通过map找到集合。 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;} 

例题5-6

通过两个队列来模拟题中队列,通过map将两个队列进行连接。

#include<iostream>#include<queue>#include<map>using namespace std;const int maxt=1000+10;int main(){//freopen("datain.txt","r",stdin);//freopen("dataout.txt","w",stdout);int t,kase=1;while(cin>>t&&t){cout<<"Scenario #"<<kase++<<endl; map<int,int> team;for(int i=0;i<t;i++){int n,x;cin>>n;while(n--){cin>>x;team[x]=i;}}queue<int> q,q2[maxt];//q为团队队列,q2每个团队的队列 for(;;){int x;string cmd;cin>>cmd;if(cmd[0]=='S') break;else if (cmd[0]=='D'){int t=q.front();cout<<q2[t].front()<<endl;q2[t].pop();if(q2[t].empty()){q.pop();}}else if(cmd[0]=='E'){cin>>x;int t=team[x];if(q2[t].empty()){q.push(t);}q2[t].push(x);}}cout<<endl;}return 0;}

例题5-7

丑数的生成方法和优先队列的使用。

#include<iostream>#include<vector>#include<queue>#include<set>using namespace std;typedef long long LL;const int coeff[3]={2,3,5}; int main(){priority_queue<LL,vector<LL>,greater<LL> > pq;set<LL> s;pq.push(1);s.insert(1);for(int i=1;;i++){LL x=pq.top();pq.pop();if(i==1500){cout<<"The 1500'th ugly number is "<<x<<".\n";break;}for(int j=0;j<3;j++){LL x2=x*coeff[j];if(!s.count(x2)){s.insert(x2);pq.push(x2);}}}return 0;}

大整数类(不完全)

struct BigInterger{static const int BASE=100000000;//每个vector存储小于BASE的数 static const int WIDTH=8;//BASE 0 的个数。用于字符串输入的时候处理 vector<int> s;BigInterger(long long num=0)//struct 中的构造函数 {*this = num;}BigInterger operator = (long long num){s.clear();do{s.pushback(num%BASE);num=num/BASE;}while(num > 0);return *this;}BigInterger operator = (const string &str){s.clear();int x ,len=(str.length()-1)/WIDTH+1;for(int i=0;i<len;i++){int end=str.length()-i*WIDTH;int start=max(0,end-WIDTH);sscanf(str.substr(start,end-start).c_str(),"%d",&x);s.push_back(x);}return *this;}BigInterger operator + (const BigInterger &b) const{}};   ostream& operator << (ostream &out,const BigInteger &x){out << x.s.back();for(int i=x.s.size()-2;i>=0;i--){char buf[20];sprintf(buf,"%08d",x.s[i]);//%8指的是WIDTH,将整形转化为字符型 for(int j=0;j<strlen(buf);j++)out<<buf[j];}return out;}istream& operator >> (istream &in,BigInterger &x){string s;if(!(in>>s)) return in;x = s;//=号已经被重载 return in;}

例题5-8

主要是格式控制。书中的代码更加简洁

#include<iostream>#include<vector>#include<string>#include<algorithm>#include<cmath>using namespace std;const int maxn=100+20;int main(){//freopen("datain.txt","r",stdin);//freopen("dataout.txt","w",stdout);int n;while(cin>>n){string input[maxn];int len=0,row=0,col=0;for(int i=0;i<n;i++){cin>>input[i];if(input[i].length()>len){len=input[i].length();}}col = (60-len)/(len+2)+1;row = ceil(double(n)/col); sort(input,input+n);for(int i=0;i<60;i++) cout<<"-";cout<<endl;for(int i=0;i<row;i++){for(int j=0;j<col;j++){if(i+(j)*row<n){cout<<input[i+j*row];if(j<col-1&&i+(j+1)*row<n){for(int k=0;k<(len+2)-input[i+j*row].length();k++)cout<<" ";}else{for(int k=0;k<(len)-input[i+j*row].length();k++)cout<<" ";}}}cout<<endl;}}return 0;} 

例题5-9

本题主要注意通过逗号分割的读入方式,使用getline方法也可以,但是时间过长,建议使用getchar(),使用getchar()注意回收回车。另外一点是pair的使用。

#include<iostream>#include<map>#include<string>#include<sstream>#include<vector>using namespace std;const int maxn=10000+10;const int maxm=10+10;typedef pair<int,int> Pair;map<Pair,int> IDcache;map<string,int> strint;  int ID(string &token) { if(strint.count(token)) { return strint[token]; }  return strint[token]=strint.size()-1; }   int findpair(Pair p,int rindex) { if(IDcache.count(p)) { return IDcache[p]; } else { IDcache[p]=rindex; return -1; }  }int main(){//freopen("datain.txt","r",stdin);//freopen("dataout.txt","w",stdout);int n,m;while(cin>>n>>m){int rindex=-1;int flag=0;    char ch;    string tmp[maxn][maxm];        getchar();        for (int i = 0; i < n; i++) {            for (int j = 0; j < m; j++) {                tmp[i][j] = "";                while ((ch = getchar()) != ',' && ch != '\n')                  tmp[i][j] += ch;//在原来的sting后面加入新的字符             }        }/*vector<string> tmp[maxn];//也可以通过getline读入,但是花费时间过长 for(int i=0;i<n;i++){string ss;cin>>ss;stringstream sstr(ss);string token;while(getline(sstr, token, ',')){tmp[i].push_back(token);}} */for(int p=0;p<m;p++){if(flag) break;for(int q=p+1;q<m;q++){if(flag) break;IDcache.clear();    strint.clear();for(int k=0;k<n;k++){Pair pr(ID(tmp[k][p]),ID(tmp[k][q]));rindex=findpair(pr,k);if(rindex!=-1&&!flag){cout<<"NO"<<endl;cout<<rindex+1<<" "<<k+1<<endl;cout<<p+1<<" "<<q+1<<endl;flag=1;break;}}} }if(!flag){cout<<"YES"<<endl;}}return 0;} 

习题5-1

本题目通过合适的方法对输入数据读取,在读取中,存储各个字符串的长度。使用迭代器对vector进行遍历。

#include<iostream>#include<string>#include<cstring>#include<sstream>#include<vector>using namespace std;void print(string s,int len){cout<<s;for(int i=0;i<=len-s.length();i++){cout<<" ";}}int main(){//freopen("datain.txt","r",stdin);//freopen("dataout.txt","w",stdout);int i=0,rows=0,j=0;vector<string> words[1000];int len[1000][200];int maxlen[200];string s,buf;memset(len,0,sizeof(len));memset(maxlen,0,sizeof(maxlen));while(getline(cin,s)){stringstream ss(s);while(ss >> buf) {words[i].push_back(buf);len[i][j++]=buf.length();}i++;j=0;rows++;}for(int j=0;j<200;j++){int tmp=0;for(int i=0;i<rows;i++){if(len[i][j]>tmp){tmp=len[i][j];}}maxlen[j]=tmp;}for(int i=0;i<rows;i++){int j=0;for(vector<string>::iterator iter=words[i].begin();iter!=words[i].end();iter++){if(iter+1!=words[i].end()){ print(*iter,maxlen[j++]);}else{cout<<*iter;}     }cout<<endl;}return 0;} 

习题5-2

#include<iostream>using namespace std;const int maxn=15;void geDu(const int *v,int *tmp,int len){for (int i=0;i<len;i++){tmp[i]=v[(i+1)%len]-v[i];}}int isall0(const int *v,int len){int flag=1;for(int i=0;i<len;i++){if(v[i]!=0)flag=0;}return flag;}int main(){//freopen("datain.txt","r",stdin);//freopen("dataout.txt","w",stdout);int n;cin>>n;while(n--){int len,flag=0;cin>>len;int v[maxn];for(int i=0;i<len;i++){cin>>v[i];}if(isall0(v,len)){cout<<"ZERO"<<endl;break;flag=1;}for(int i=0;i<1000;i++){ int tmp[maxn];geDu(v,tmp,len);if(isall0(v,len)){cout<<"ZERO"<<endl;flag=1;break;}for(int i=0;i<len;i++){v[i]=tmp[i]; }}if(!flag){cout<<"LOOP"<<endl;}}return 0;} 

习题5-3

队列的使用,注意q.pop()不会返回元素,只是表示出队列。使用q.front()来获得队前元素。

#include<iostream>#include<queue>using namespace std;int main(){//freopen("datain.txt","r",stdin);//freopen("dataout.txt","w",stdout);int n;while(cin>>n&&n){queue<int> q;for(int i=1;i<=n;i++){q.push(i);}cout<<"Discarded cards:";while(q.size()>1){int tmp;cout<<" "<<q.front();q.pop();q.push(q.front());q.pop();if(q.size()>1)cout<<",";}cout<<endl;cout<<"Remaining card: "<<q.front()<<endl;}return 0;} 

习题5-4

本题使用pair和map,输入的时候,使用map记录<出发地,目的地>的个数。输入完成,只要<出发地,目的地>的个数等于<出发地,目的地>的个数,就输出YES,否则输出NO。

#include<iostream>#include<map>using namespace std;typedef pair<int,int> Pair;int main(){//freopen("datain.txt","r",stdin);//freopen("dataout.txt","w",stdout);int n;while(cin>>n&&n){int flag=1;map<Pair,int> mp;while(n--){int a,b;cin>>a>>b;Pair pr(a,b);if(!mp.count(pr)){mp[pr]=1;}else{mp[pr]++;}}for(map<Pair,int>::iterator iter=mp.begin();iter!=mp.end();iter++){Pair a = iter->first;    Pair np(a.second,a.first);    if(mp[np]!=mp[a]){flag=0;break;}}if(flag){cout<<"YES"<<endl;}else{cout<<"NO"<<endl;}}return 0;} 

习题5-5

本题目通过拆分单词串成两个子串,如果两个子串都在输入中,则说明该串为复合单词,使用substr()来取子串,使用lower_bound()进行查找,使用find()要超时,在已经排好序后,使用lower_bound更加节省时间。

#include<iostream>#include<vector>#include<algorithm>using namespace std;int main(){//freopen("datain.txt","r",stdin);//freopen("dataout.txt","w",stdout);string a;vector<string> wd;while(cin>>a){wd.push_back(a);}for(vector<string>::iterator iter=wd.begin();iter!=wd.end();iter++){string a = *iter;//分解a;if(a.length()==1){continue;}for(int i=1;i<a.length();i++){string a1= a.substr(0,i);string a2= a.substr(i,a.length()-a1.length());vector<string>::iterator ita1,ita2;//使用find时间复杂度太高//ita1=find(wd.begin(),wd.end(),a1); //ita2=find(wd.begin(),wd.end(),a2); ita1= lower_bound(wd.begin(), wd.end(), a1);                                                    ita2= lower_bound(wd.begin(), wd.end(), a2);                                                               if (*ita1 == a1 && *ita2 == a2){              cout << *iter << endl;              break;          }              }}//for(set<string>::iterator iter=res.begin();iter!=res.end();iter++)//{//cout<<*iter<<endl;//}return 0;} 

习题5-6

本题我的代码不是很简洁。简单梳理下思路,先根据点的数量,确定对称轴的x坐标。在对称轴上的点,是对称。不在对称轴上的点需要找到一个关于这个对称轴对称的点。那么需要使用到排序,如果前面的一半的点都能找到他对应的点,那么就对称,否则不对称。

#include<iostream>#include<vector>#include<algorithm>#include<cmath>using namespace std;struct Point {int x;int y;};bool operator == (const Point &a,const Point &b){if(a.x==b.x&&a.y==b.y)return true;elsereturn false;}bool cmp(const Point &a,const Point &b){if(a.x<b.x)return true;return false;}int main(){//freopen("datain.txt","r",stdin);//freopen("dataout.txt","w",stdout);int n;cin>>n;while(n--){int m;vector<Point> vp;cin>>m;int z=m;while(z--){int x,y;cin>>x>>y;struct Point p={x,y};vp.push_back(p);}sort(vp.begin(),vp.end(),cmp);//for(vector<Point>::iterator it=vp.begin();it!=vp.end();it++)//{//cout<<it->x<<" ";//cout<<it->y<<endl;//}if(m%2==1){int isout=0;int midx=vp[m/2].x;for(int i=0;i<m/2;i++){int x1,y1;int flag=0;x1=midx+(midx-vp[i].x);y1=vp[i].y;struct Point p1={x1,y1};for(vector<Point>::iterator it=vp.begin();it!=vp.end();it++){if(*it==p1||p1.x==midx){flag=1;break;}}if(!flag){cout<<"NO"<<endl;isout=1;break;}}if(!isout){cout<<"YES"<<endl;}}else{int isout=0;int midx1=vp[m/2].x;int midx2=vp[m/2-1].x;int dc= (2*midx2+(midx1-midx2))/2;for(int i=0;i<m/2;i++){int x1,y1;int flag=0;x1=vp[i].x+(2*midx2+(midx1-midx2)-2*vp[i].x);y1=vp[i].y;struct Point p1={x1,y1};for(vector<Point>::iterator it=vp.begin();it!=vp.end();it++){if(*it==p1||p1.x==dc){flag=1;break;}}if(!flag){cout<<"NO"<<endl;isout=1;break;}}if(!isout){cout<<"YES"<<endl;}}}return 0;} 

习题5-7

本题使用Queue,构建一个有优先级和标识是否为自己任务的结构体,根据题目要求一步一步进行即可。可以注意一下遍历队列的方法。

#include<iostream>#include<queue>using namespace std;typedef struct job{int priority;int isself;}Job;int main(){//freopen("datain.txt","r",stdin);//freopen("dataout.txt","w",stdout);int m;cin>>m;while(m--){int qn,p;queue<Job> qujob;cin>>qn>>p;for(int i=0;i<qn;i++){int pri;cin>>pri;Job tj;tj.priority=pri;if(i==p){tj.isself=1;}else{tj.isself=0;}qujob.push(tj);}int time=0;while(!qujob.empty()){Job fj=qujob.front();qujob.pop();int flag=0;for(int i=0;i<qujob.size();i++)//队列遍历 {Job tmp=qujob.front();if(tmp.priority>fj.priority){flag=1;}qujob.pop();qujob.push(tmp);}if(flag){qujob.push(fj);}else{if(fj.isself==1){time++;cout<<time<<endl;break;}else{time++;}}}}return 0;}

习题5-8

本题目主要是要审题对,一开始因为对题目没有理解透彻,出现一些错误。比如题目中没有告诉一开始书架上的书的摆放是按照输入顺序排序好了还是按照输入顺序。根据测试是摆放的书籍已经拍好序。又比如在shelve命令的时候,是按照还书的顺序放入暑假,还是先将还书进行排序后再放入书架。经过测试,是先将还书排序后,再依次放入书架。


#include<iostream>#include<string>#include<vector>#include<algorithm>#include<map>#include<set>using namespace std;struct Book{string title;string author;};bool operator < (const Book &a,const Book &b){if(a.author<b.author)return true;    if (a.author==b.author)if(a.title<b.title)return true;return false;}bool cmp(const Book &a,const Book &b){return a<b;}int main(){//freopen("datain.txt","r",stdin);//freopen("dataout.txt","w",stdout);string s;map<string,string> Bks;vector<Book> Sbks;set<Book> Rbks;while(getline(cin,s)&&s!="END"){string s1,s2;int k = s.find('"', 1);        s1 = s.substr(0, k+1);        s2 = s.substr(k+5);Book bk;bk.author=s2;bk.title=s1;Bks[s1]=s2;Sbks.push_back(bk);}sort(Sbks.begin(),Sbks.end(),cmp);while(getline(cin,s)&&s!="END"){string s1,s2;int k=s.find(' ', 1);        s1=s.substr(0, k);        s2=s.substr(k+1);if(s1[0]=='R'){Book bk1;bk1.title=s2;bk1.author=Bks[s2];Rbks.insert(bk1);}else if (s1[0]=='B'){for(vector<Book>::iterator it=Sbks.begin();it!=Sbks.end();){if(it->title==s2){Sbks.erase(it);break;}elseit++;}}else if (s1[0]=='S'){for(set<Book>::iterator it1=Rbks.begin();it1!=Rbks.end();it1++){Book bk1;bk1=*it1;vector<Book>::iterator it2 = lower_bound(Sbks.begin(),Sbks.end(),bk1);                cout << "Put " << it1->title;                if (Sbks.empty() || it2 == Sbks.begin())                  cout << " first" << endl;                else                  cout << " after " << (it2-1)->title << endl;                  Sbks.insert(it2,bk1);}cout<<"END"<<endl;Rbks.clear();}}return 0;} 








阅读全文
0 0