1.vector
题目:https://vjudge.net/contest/310193#problem/A
代码:
#include<cstdio> #include<string> #include<vector> #include<iostream> using namespace std; const int maxn = 30; int n; vector<int> pile[maxn]; //查找木块a所在的pile和height 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; } } } } //把第p堆高度为h的木块上方的所有木块放回原位 void clearAbove(int p,int h) { for (size_t i = h+1; i < pile[p].size(); i++) { int b = pile[p][i]; pile[b].push_back(b);//把木块b放回原位 } pile[p].resize(h + 1);//只保留第0-h元素 } //把第p堆高度为h及以上的移动到p2顶部 void pileonto(int p,int h,int p2) { for (size_t i = h; i < pile[p].size(); i++) { pile[p2].push_back(pile[p][i]); } pile[p].resize(h); } //输出 void print() { for (size_t i = 0; i < n; i++) { printf_s("%d", i); for (size_t j = 0; j < pile[i].size(); j++) { printf_s(" %d", pile[i][j]); } printf_s("\n"); } } int main() { int a, b; cin >> n; string s1, s2; for (size_t 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") clearAbove(pb, hb); if (s1 == "move") clearAbove(pa, ha); pileonto(pa, ha, pb); } print(); return 0; }
数据结构核心vector<int> pile[maxn]
每一个木块堆的高度不确定,所以用vector来保存比较合适,而木块堆的个数不超过n,所以用一个数组来存储就可以。
2.set
题目:https://vjudge.net/contest/310193#problem/B
代码:
#include<iostream> #include<string> #include<set> #include<sstream> using namespace std; set<string> dict; //为字典设置一个名为dict-short的集合,它基于字符串类型; int main(){ string s,buf; while (cin>>s){ for (int i=0;i<s.length();i++) if (isalpha(s[i])) //isalpha函数:判断字符ch是否为英文字母,若为英文字母,返回非0.若不是字母,返回0 s[i]=tolower(s[i]); //如果它是一个字母,把它变成小写。 else s[i]=' '; stringstream ss(s); //如果是空格,忽略它 while (ss>>buf) dict.insert(buf); //插入到已经是有序的集合, } for (set<string>::iterator it=dict.begin();it!=dict.end();++it)//迭代器就像一个点,从头到尾扫描它并输出 cout<<*it<<endl; return 0; }
set是数学上的集合,它是一个不包含重复元素的集合,并且自动重小到大排序。输入时把所有非字母的字符变成空格,然后利用stringstream得到各个单词。
3.map
题目:https://vjudge.net/contest/310193#problem/C
代码:
#include <iostream> #include <string> #include <vector> #include <map> #include <algorithm> #include <cstring> using namespace std; vector<string> v; map<string,int> q; int main() { string s; while(cin >> s) { if(s == "#") break; else { v.push_back(s); int l = s.size(); for(int i = 0; i < l; i++) { if(s[i] >= 65 && s[i] <= 90) { s[i] += 32; } } sort(s.begin(),s.end()); q[s]++; } } int n = v.size(); sort(v.begin(),v.end()); string t; for(int i = 0;i < n; i++) { t = v[i]; int len = t.size(); for(int i = 0; i < len; i++) { if(t[i] >= 65 && t[i] <= 90) { t[i] += 32; } } sort(t.begin(),t.end()); if(q[t]==1) cout << v[i] << endl; } return 0; }
就是查找字母重组后出现一次的单词;先将单词变为小写并按字典序排列,用map容器存储单词,然后用其映射表示出现其次数。最后将出现一次的单词保存到set中,将其输出。
4.queue的使用
题目:https://vjudge.net/contest/310193#problem/D
代码:
#include<bits/stdc++.h> #include<queue> #include<map> using namespace std; const int maxn=1000+10; int main(){ int t,cnt=0; while(scanf("%d",&t)==1&&t){ printf("Scenario #%d\n",++cnt); map<int,int>team; for(int i=0;i<t;i++){ int n,x; scanf("%d",&n); while(n--){ cin>>x; team[x]=i; } } queue<int>q,q2[maxn]; for(;;){ int x; char cmd[10]; scanf("%s",cmd); if(cmd[0]=='S') break; else if(cmd[0]=='D'){ int t=q.front(); printf("%d\n",q2[t].front()); q2[t].pop(); if(q2[t].empty()) q.pop(); } else if(cmd[0]=='E'){ scanf("%d",&x); int t=team[x]; if(q2[t].empty()) q.push(t); q2[t].push(x); } } printf("\n"); } return 0; }
用到两个队列,一个是每个团队自己是一个队列,而每个团队整体之间又构成一个队列。
5.优先队列的使用
题目:https://vjudge.net/contest/310193#problem/E
代码:
#include<bits/stdc++.h> #include<queue> #include<vector> #include<set> using namespace std; typedef long long ll; priority_queue<int,vector<ll>,greater<ll> >pq; set<ll>s; const int coo[3]={2,3,5}; int main(){ 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*coo[j]; if(!s.count(x2)){ s.insert(x2); pq.push(x2); } } } return 0; }
丑数的2,3,5倍仍然是丑数(排除重复的)
6.全排列函数
题目:https://vjudge.net/contest/310193#problem/F
代码:
#include<iostream> #include<algorithm> #include<cstring> using namespace std; const int maxn=10010; int num[maxn]; int main() { int n,m; while(cin>>n>>m){ int cnt=1; memset(num,0,sizeof(num)); for(int i=0;i<n;i++){ num[i]=i+1; } while(true){ if(cnt==m){ cout<<num[0]; for(int i=1;i<n;i++){ cout<<" "<<num[i]; } cout<<"\n"; break; } next_permutation(num,num+n); cnt++; } } return 0; }
emmm……next_permutation(num,num+n)函数的用法考察
7.拓扑排序
题目:https://vjudge.net/contest/310193#problem/G
代码:
#include<cstdio> #include<cstring> #include<queue> #include<iostream> using namespace std; int ans[510][510]; int n,indegree[510]; queue<int>q; void topsort() { int i,j,t,top; queue<int>q; for(i=1;i<=n;++i) { if(indegree[i]==0) { q.push(i); break; } } int sign=1; while(!q.empty()) { top=q.front(); q.pop(); indegree[top]=-1; if(sign) { printf("%d",top); sign=0; } else printf(" %d",top); for(i=1;i<=n;++i)//注意,以当前第一名为前驱的点的前驱数量都要减少 { if(ans[top][i]==1) indegree[i]--; } for(i=1;i<=n;++i) { if(indegree[i]==0) { q.push(i); break; } } } printf("\n"); } int main() { int i,m,u,v; while(cin>>n>>m){ memset(indegree,0,sizeof(indegree)); memset(ans,0,sizeof(ans)); while(m--){ cin>>u>>v; if(ans[u][v]==0){ ans[u][v]=1; indegree[v]++; } } topsort(); } return 0; }
将输入的数据存到图中,同时更新入度的数组。在拓扑排序时,首先找到入度为0 的点,接着遍历所有的点,看是不是这个入度为0 的点的邻接点。如果是,那么入度-1。字典序的控制依赖于刚开始的循环。并且,在没有入度为0的仍然按照字典序存入res数组。
8.拓扑排序2
题目:https://vjudge.net/contest/310193#problem/H
代码:
#include<iostream> #include<vector> #include<queue> using namespace std; const int maxn=1e5+10; vector<int>vec[maxn]; queue<int>q; int indeg[maxn]; int n,m; bool topsort(){ int num=0; while(!q.empty()) q.pop(); for(int i=0;i<n;i++){ if(!indeg[i]) q.push(i); } while(!q.empty()){ int now=q.front(); q.pop(); num++; for(int i=0;i<vec[now].size();i++){ if(--indeg[vec[now][i]]==0){ q.push(vec[now][i]); } } } if(num==n)return true; return false; } int main(){ while(true){ cin>>n>>m; if(n==0) break; for(int i=0;i<n;i++){//清空 vec[i].clear(); indeg[i]=0; } memset(indeg,0,sizeof(indeg)); while(m--){ int u,v; cin>>u>>v; vec[u].push_back(v); indeg[v]++; } if(topsort()){ puts("YES"); } else puts("NO"); } return 0; }
思路同一
9,10并查集水题(改下输入输出)
模板:
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std; const int maxn = 30005; int f[maxn], rank[maxn];//f[]是根节点,rank[]是 根节点的高度 int find_root(int x) //查找根节点 { if(x != f[x]) f[x] = find_root(f[x]); return f[x]; } int main() { int n,m,k; while(cin>>n>>m) { if(n==0&&m==0) break; int a, b; for(int i = 0; i < n; i++) { f[i] = i; rank[i] = 0; } if(m == 0) { printf("1\n"); continue; } while(m--) //输入各个集合 { cin>>k; k--; cin>>a; while(k--) { cin>>b; a = find_root(a); b = find_root(b); if(rank[a]>rank[b]){ //高度更高的为根节点 f[b] = a; } else{ f[a] = b; if(rank[a] == rank[b]) rank[b]++; } a = b; } } int ans = 0, x = find_root(0); for(int i=0; i<n; i++) { if(find_root(i) == x) ans++; //这里不能写f[i]==x,会出错,要再更新一次根节点才行 } printf("%d\n", ans); } return 0; }
11.反向拓扑
#include<algorithm> #include<iostream> #include<cstring> #include<vector> #include<queue> using namespace std; const int maxn=10005; queue<int>q; vector<int>vec[maxn]; int indeg[maxn],array[maxn]; int n,m; int topsort(){ while(!q.empty()) q.pop(); for(int i=1;i<=n;i++){ if(!indeg[i]) { q.push(i); } } int num=0; while(!q.empty()){ int now=q.front(); q.pop(); num++; for(int i=0;i<vec[now].size();i++){ if(--indeg[vec[now][i]]==0){ q.push(vec[now][i]); array[vec[now][i]]=max(array[now]+1,array[vec[now][i]]); } } } if(num!=n) return -1; int sum=0; for(int i=1;i<=n;i++) sum+=array[i]+888; return sum; } int main(){ while(cin>>n>>m){ memset(vec,0,sizeof(vec)); memset(indeg,0,sizeof(indeg)); memset(array,0,sizeof(array)); while(m--){ int u,v; cin>>u>>v; vec[v].push_back(u); indeg[u]++; } cout<<topsort()<<endl; } return 0; }