1101 Quick Sort
题目大意:给出一个含N个不同数的序列,该序列是某趟快速排序的中间结果,求哪些数可能是该趟的基准数据pivot
解题思路:
题目等价于求哪些数满足:左边区间的数均小于它,右边区间的数均大于它
这题关键在于跑测试数据容易超时
题目再等价于求哪些数满足:大于它左边区间的最大值(maxArr[i]),小于它右边区间的最小值(minArr[i])
这样就可以从暴力代码的复杂度O(n^2)降到O(n)
// 编程关键的代码段
int minArr[MAXN]; // [i, N]区间中的最小数值
int maxArr[MAXN]; // [1, i]区间中的最大数值
maxArr[0]=0;
for(int i=1; i<=N; i++) {
cin>>input[i];
maxArr[i] = maxArr[i-1] > input[i] ? maxArr[i-1] : input[i];
}
minArr[N+1]=INT_MAX;
for(int i=N; i>0; i--) {
minArr[i] = minArr[i+1] < input[i] ? minArr[i+1] : input[i];
if(minArr[i]>=input[i] && maxArr[i]<=input[i])
ans.push_back(input[i]);
}
1102 Invert a Binary Tree
题目大意:构造一棵二叉树,并输出层序序列和中序序列。
题目较为简单
1103 Integer Factorization
题目大意:给定N、K、P三个数,求K个数,使得这K个数的P次方的和 恰好等于N
解题思路:我是用了DFS求解
#include <iostream>
#include <cmath>
using namespace std;
const int MAXN=401;
int N, K, P;
int temp[MAXN],resPath[MAXN],maxKsum=0;
int flag=0; // 该变量记录是否找到一个解
int exp(int n,int p) { // 求n的p次幂 快速幂算法
int res=1;
while(p>0) {
if(p%2==1)
res*=n;
p/=2;
n*=n;
}
return res;
}
int GetMax() { // 判断k个数中,可能的最大值,控制递归边界
for(int i=1; i<=400; i++) {
if(exp(i,P)>=(N-K+1))
return i;
}
return -1;
}
bool jud() {
for(int i=K; i>=1; i--) {
if(temp[i]>resPath[i])
return true;
}
return false;
}
void Copy() {
for(int i=1; i<=K; i++)
resPath[i] = temp[i];
}
void DFS(int startnum,int curSum,int stackLevel,int ksum) {
if(stackLevel==K) {
if(curSum==N) {
flag=1;
temp[stackLevel]=startnum;
if(ksum>maxKsum) {
maxKsum = ksum;
Copy();
} else if(ksum==maxKsum && jud()) {
Copy();
}
}
} else {
if(curSum>=N) // 剪枝
return;
temp[stackLevel]=startnum;
for(int i=startnum; i>=1; i--)
DFS(i,curSum+exp(i,P),stackLevel+1,ksum+i);
}
}
int main() {
cin>>N>>K>>P;
DFS(GetMax(),0,0,0);
if(flag==0)
cout<<"Impossible"<<endl;
else {
cout<<N<<" = ";
for(int i=1; i<=K; i++) {
if(i>1)
cout<<" + ";
cout<<resPath[i]<<"^"<<P;
}
cout<<endl;
}
return 0;
}
1104 Sum of Number Segments(重要)
题目大意:n个数,有n(1+n)/2种排列组合,组合里所有元素总和代表该组合的值,求所有排列组合的值的总和
解题思路:题意转换为求每个数 Ni 在所有组合里出现的次数 Ti,就是所求结果。
其实一看到这个题目,跟数学的相关性很强,就可以考虑是否存在一个函数F,使得F(N, i) = Ti
T1 | T2 | T3 | T4 | T5 | T6 | T7 | |
---|---|---|---|---|---|---|---|
N=1 | 1 | ||||||
N=2 | 2 | 2 | |||||
N=3 | 3 | 4 | 3 | ||||
N=4 | 4 | 6 | 6 | 4 | |||
N=5 | 5 | 8 | 9 | 8 | 5 | ||
N=6 | 6 | 10 | 12 | 12 | 10 | 6 | |
N=7 | 7 | 12 | 15 | 16 | 15 | 12 | 7 |
不难确定函数F:F(N, i) = i * (N-i+1) = Ti,所以就是题目需要的结果
但是这个题我做的时候,真的没有考虑到它对double精度的要求很高。因为题目给出的Ni都是很小的小数,多次的double相加会造成一定的误差!!!,导致代码未通过测试用例。解决的办法是:将输入值乘以1000,sum值用long long型计算,最后输出除以1000.0保留两位小数
为什么是乘以1000?
我测试了几次,发现乘以100或者10000均不能通过测试用例,自己猜测:题目要求的精度是小数点后2位,所以乘以10的( 2+1 )次幂
#include <cstdio>
int main() {
double elem;
long long sum=0;
int N;
scanf("%d",&N);
for(int i=1; i<=N; i++) {
scanf("%lf",&elem);
sum+=(long long)(elem*1000)*i*(N-i+1);
}
printf("%.2lf\n",sum/1000.0);
return 0;
}
1106 Lowest Price in Supply Chain
题目大意:寻找一棵树所处层级最小的叶结点,确定最小层级,并确定这样的叶结点有多少个
解题思路:采用DFS+剪枝的方法
#include <iostream>
#include <vector>
#include <cstdio>
using namespace std;
const int MAXN=1e5+10;
vector<int> graph[MAXN];
int minLevel=-1,num=-1;
double getPrice(double r,double p,int level) {
double res = p;
for(int i=1; i<=level; i++) {
res*=(1.0+r);
}
return res;
}
void DFS(int root,int level) {
int len = graph[root].size();
if(len==0) { // 到达叶结点
if(minLevel==-1 || level<minLevel) {
minLevel=level,num=1;
} else if(level==minLevel) {
num++;
}
} else if(minLevel==-1 || level<minLevel) { // 剪枝,若level>=minLevel,且当前结点不是叶结点,则该路径永远不会到达最优值
for(int i=0; i<len; i++)
DFS(graph[root][i],level+1);
}
}
int main() {
int N,K,elem;
double P,r;
cin>>N>>P>>r;
for(int i=0; i<N; i++) {
cin>>K;
for(int j=1; j<=K; j++) {
cin>>elem;
graph[i].push_back(elem);
}
}
DFS(0,0);
printf("%.4lf %d\n",getPrice(r/100.0,P,minLevel),num);
return 0;
}
1107 Social Clusters
题目大意:一个兴趣部落里,成员有共同的兴趣爱好(即一个成员至少能在这个部落找到另一个成员,他们有一个共同的爱好;不是要求所有人都必须有一个共同爱好),求出每个兴趣部落有多少人,并降序输出对应的人数。
解题思路:用并查集的算法解题。起初,每个兴趣爱好即代表一个部落;若一个人有两个及以上的爱好,就相当于把这些爱好原先对应的部落进行合并,成为一个新的较大的部落;当输入完毕,部落的划分也就完毕,进行排序操作后输出对应的结果即可。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN=1001;
int arr[MAXN]; // 拥有第i个hobby的人数是arr[i]
int father[MAXN]; // 记录哪几个hobby可以组成一个聚落
int sum[MAXN]; // 选择一个根结点代表一个聚落,记录每个聚落有多少人
bool cmp(int x,int y) {
return x > y;
}
void Init() {
for(int i=0; i<MAXN; i++) {
father[i] = i;
sum[i]=0;
arr[i]=0;
}
}
int Find(int x) {
if(x!=father[x])
father[x] = Find(father[x]); // 进行了路径压缩
return father[x];
}
void Union(int x,int y) {
int fax = Find(x);
int fay = Find(y);
if(fax!=fay) {
father[fax] = fay;
}
}
int main() {
Init();
int N,K,elem,elem2;
cin>>N;
for(int i=1; i<=N; i++) {
scanf("%d: %d",&K,&elem);
arr[elem]++;
for(int i=2; i<=K; i++) {
cin>>elem2;
// arr[elem2]++; 这句话必须注释掉,因为聚落合并后,人数会有重叠的地方
Union(elem,elem2);
}
}
for(int i=1; i<MAXN; i++)
sum[Find(i)]+=arr[i];
sort(sum,sum+MAXN,cmp);
int pos=0;
while(sum[pos]>0)
pos++;
cout<<pos<<endl;
for(int i=0; i<pos; i++) {
if(i>0)
cout<<" ";
cout<<sum[i];
}
cout<<endl;
return 0;
}
1108 Finding Average(重要)
题目大意:一道纯粹考字符串操作的题目
解题思路:
遇到考字符串的题目真的要多尝试用sscanf来处理,如果用熟练了真的方便好多
这里参考大神的代码,我本来自己手动写了判断字符串的函数,代码提交测试的时候,一直通不过测试,只好放弃。实在是判断的细节太多了,题目有些又没讲清楚。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int main() {
char old[1000],now[1000];
int N,num=0;
double sum=0;
cin>>N;
for(int i=0; i<N; i++) {
double temp;
scanf("%s",old);
sscanf(old,"%lf",&temp);
sprintf(now,"%.2lf",temp);
int flag=1;
for(int j=0; j<strlen(old) && flag==1; j++)
if(old[j]!=now[j])
flag=0;
if(flag==0 || temp<-1000 || temp>1000){
printf("ERROR: %s is not a legal number\n",old);
continue;
}
else {
num++;
sum+=temp;
}
}
if(num==1)
printf("The average of 1 number is %.2lf\n",sum);
else if(num>1)
printf("The average of %d numbers is %.2lf\n",num,sum/num);
else
printf("The average of 0 numbers is Undefined\n");
return 0;
}
但是有个奇怪的错误是,在本地编译器环境跑的时候,把字符数组的大小改为100,会报奇怪的错误,过段时间再测试,又能跑通了。难道是跟电脑本地动态环境有关系吗?
1109 Group Photo
就是一道排序+模拟题
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN=1e4+10;
struct Person {
int height;
string name;
Person() {}
Person(int h,string n):height(h),name(n) {}
bool operator< (const Person& y) const {
if(height!=y.height)
return height < y.height;
return name > y.name;
}
} person[MAXN];
void PrintRow(int left,int right) { // [left, right]是闭区间
int len = right-left+1,flag=0;
int pos = len%2==0 ? left : left+1;
for(; pos<right; pos+=2) {
if(flag==0)
flag=1;
else
cout<<" ";
cout<<person[pos].name;
}
for(pos=right; pos>=left; pos-=2) {
if(flag==0)
flag=1;
else
cout<<" ";
cout<<person[pos].name;
}
cout<<endl;
}
int main() {
int N,K,h;
string elem;
cin>>N>>K;
for(int i=1; i<=N; i++) {
cin>>elem>>h;
person[i] =Person(h,elem);
}
sort(person+1,person+1+N);
int rowLen=N/K;
PrintRow(1+rowLen*(K-1),N);
for(int row=K-1; row>=1; row--)
PrintRow(1+rowLen*(row-1),rowLen*row);
return 0;
}
1110 Complete Binary Tree
题目大意:给定一棵二叉树,结点个数为N,判断其是否是完全二叉树
解题思路:对树进行层序遍历,用-1表示子结点为空,若遍历到的前N个结点都是不为空的结点,则该树为完全二叉树;反之则不是。
1111 Online Map
就是一道考Dijkstra算法的知识,解题思路可以参考这篇文章
1112 Stucked Keyboard
又是一道字符串的操作题,感觉直接看代码吧。很搞笑的是,题目给的样例数据k=3,我写代码的时候直接用了3而不是k,半天没反应过来这个低级错误
#include <iostream>
#include <map>
#include <climits>
#include <vector>
using namespace std;
const int MAXN = 26+10+1+1;
int isStucked[MAXN],vis[MAXN];
map<char,int> myMap; // 给字符编号,简化后续处理
map<int, char> myMap2;
void Init() {
for(int i=0; i<MAXN; i++)
isStucked[i]=1,vis[i]=0;
int index=0;
for(int i=0; i<26; i++) {
char temp = 'a' + i;
myMap[temp] = index;
myMap2[index++]=temp;
}
for(int i=0; i<10; i++) {
char temp = '0' + i;
myMap[temp] = index;
myMap2[index++]=temp;
}
myMap['_'] = index;
myMap2[index++]='_';
}
int main() {
Init();
int k,j;
string str,res="";
vector<char> resKey;
cin>>k>>str;
int len = str.size(); // 由于题目保证会有一个stucked key,k>1,所以len>1一定成立
for(int i=0; i<len;) { // 这里没有考虑进最后一个字符
for(j=1; j<k&&i+j<len; j++)
if(str[i]!=str[i+j])
break;
if(j<k)
isStucked[myMap[str[i]]]=0,i++;
else
i+=k;
}
for(int i=0; i<len;) {
res+=str[i];
if(isStucked[myMap[str[i]]]==1) {
if(vis[myMap[str[i]]]==0) {
resKey.push_back(str[i]);
vis[myMap[str[i]]]=1;
}
i+=k;
} else {
i++;
}
}
for(int i=0; i<resKey.size(); i++)
cout<<resKey[i];
cout<<endl<<res<<endl;
return 0;
}
1113 Integer Set Partition
就是一道很简单的排序题
1114 Family Property
并查集的一道题目,不知道为什么我做了好久,可能我的方法用得不对
#include <iostream>
#include <vector>
#include <set>
#include <climits>
#include <algorithm>
#include <cstdio>
using namespace std;
const int MAXN=10001;
struct Person {
int M;
int area;
Person():M(-1),area(-1) {}
} persons[MAXN];
struct Family {
int ID;
set<int> members;
int numArea;
int sumArea;
Family():ID(INT_MAX),numArea(-1),sumArea(-1) {}
bool operator< (const Family& y) const {
int num1 = members.size();
int num2 = y.members.size();
if(numArea==-1)
return false;
if(y.numArea==-1)
return true;
if(sumArea*num2 != y.sumArea*num1)
return sumArea*num2 > y.sumArea*num1;
return ID < y.ID;
}
} family[MAXN];
int father[MAXN];
void Init() {
for(int i=0; i<MAXN; i++) {
father[i]=i;
}
}
int Find(int x) {
if(x!=father[x])
father[x] = Find(father[x]); // 实现了路径压缩
return father[x];
}
void Union(int x,int y) {
int fax = Find(x);
int fay = Find(y);
if(fax!=fay) {
father[fax] = fay;
}
}
int main() {
Init();
int N;
cin>>N;
for(int i=0; i<N; i++) {
int id,fa,ma,k,elem;
cin>>id>>fa>>ma>>k;
if(fa!=-1)
Union(id,fa);
if(ma!=-1)
Union(id,ma);
for(int j=0; j<k; j++) {
cin>>elem;
Union(id,elem);
}
cin>>persons[id].M>>persons[id].area;
}
for(int i=0; i<MAXN; i++) {
int fa = Find(i);
family[fa].members.insert(i);
family[fa].ID = min(family[fa].ID, i);
if(persons[i].M!=-1) {
if(family[fa].numArea==-1)
family[fa].numArea=persons[i].M;
else
family[fa].numArea+=persons[i].M;
}
if(persons[i].area!=-1) {
if(family[fa].sumArea==-1)
family[fa].sumArea=persons[i].area;
else
family[fa].sumArea+=persons[i].area;
}
}
sort(family,family+MAXN);
int numFamily = 0;
while(numFamily<N && family[numFamily].sumArea!=-1)
numFamily++;
cout<<numFamily<<endl;
for(int i=0; i<numFamily; i++) {
int mem = family[i].members.size();
printf("%04d %d %.3lf %.3lf\n",family[i].ID,mem,(double)family[i].numArea/(double)mem,(double)family[i].sumArea/(double)mem);
}
return 0;
}
1115 Counting Nodes in a BST
一道简单的二叉搜索树
1116 Come on! Let's C
一道简单的分支判断题
1117 Eddington Number
这题其实就是排序题,我理解完题意,竟然用树状数组做,结果还超时了,真的是小题大做。
做题的时候切忌,要多想想几种可能的算法,然后尽量选择编程容易、效率高的那个,有时候不要给自己增加代码难度。
// 这段代码已通过测试用例
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN=1e5+10;
int arr[MAXN];
int main() {
int N,i,j,res=-1;
cin>>N;
for(i=0; i<N; i++)
cin>>arr[i];
sort(arr,arr+N);
for(int i=N;i>=0;i--){
if(i==0){ // 这个是针对测试点4:所有arr[i]均为 0
cout<<i<<endl;
break;
}
if(arr[N-i]>i){ // 有i-1个数大于等于arr[N-i], 这句判断等价于至少有i个数大于i
cout<<i<<endl;
break;
}
}
return 0;
}
// 强行弄的树状数组算法,并未通过测试用例
#include <iostream>
using namespace std;
const int MAXN=1e5+10;
int lowbit(int x) {
return x&(-x);
}
int arr[MAXN];
int GetSum(int x) {
int res=0;
for(int i=x; i>0; i-=lowbit(i))
res+=arr[i];
return res;
}
void Update(int x,int val) {
for(int i=x; i<MAXN; i+=lowbit(i))
arr[i]+=val;
}
int main() {
fill(arr,arr+MAXN,0);
int N,elem,maxNum=0;
cin>>N;
for(int i=0; i<N; i++) {
cin>>elem;
maxNum=max(maxNum,elem);
Update(elem,1);
}
int flag=0;
for(int i=min(maxNum,N); i>0; i--) {
if(N-GetSum(i)>=i) {
flag=1;
cout<<i<<endl;
break;
}
}
if(flag==0)
cout<<0<<endl;
return 0;
}
1118 Birds in Forest
题目大意:求有多少只鸟和多少棵树,并判断两只鸟是否在同一棵树上
解题思路:一道基础的并查集
1119 Pre- and Post-order Traversals(重要)
题目大意:给出一棵二叉树的先序、后序遍历序列(树的点权值均不相同),求它的中序遍历序列(若有多种可能,输出一种结果即可)
解题思路:见代码中标注的两处注释,它们是解题的关键。有关二叉树的知识点可以参考这篇文章
#include <iostream>
using namespace std;
const int MAXN=31;
struct TreeNode {
int data;
TreeNode* left;
TreeNode* right;
TreeNode():left(NULL),right(NULL) {}
TreeNode(int d):data(d),left(NULL),right(NULL) {}
};
int preOrder[MAXN],postOrder[MAXN],flag=0,flag2=0;
TreeNode* Create(int prel,int prer,int postl,int postr) {
if(prel>prer)
return NULL;
else {
TreeNode* root = new TreeNode(preOrder[prel]);
if(prer-prel==1) { // 当子树所有结点总数之和只有1时,这个惟一的结点可能是左子树,也可能是右子树,因而答案不唯一
flag=1;
root->left = Create(prer,prer,postl,postl);
} else if(prer-prel>1) {
int sepPos = prel+1; // sepPos就是右子树的根结点,这个很关键
for(; sepPos<=prer; sepPos++) {
if(preOrder[sepPos]==postOrder[postr-1])
break;
}
root->left = Create(prel+1,sepPos-1,postl,(postr-1)-(prer-sepPos+1));
root->right = Create(sepPos,prer,(postr-1)-(prer-sepPos+1)+1,postr-1);
}
return root;
}
}
void InOrderPrint(TreeNode* root) {
if(root!=NULL) {
InOrderPrint(root->left);
if(flag2==0)
flag2=1;
else
cout<<" ";
cout<<root->data;
InOrderPrint(root->right);
}
}
int main() {
int N;
cin>>N;
for(int i=0; i<N; i++)
cin>>preOrder[i];
for(int i=0; i<N; i++)
cin>>postOrder[i];
TreeNode* root = Create(0,N-1,0,N-1);
if(flag==0)
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
InOrderPrint(root);
cout<<endl;
return 0;
}
1120 Friend Numbers
简单的模拟题,用到了set类型辅助解题
#include <iostream>
#include <set>
using namespace std;
int GetFriendID(int x) {
int res=0;
while(x>0) {
res+=(x%10);
x/=10;
}
return res;
}
int main() {
int N,elem;
cin>>N;
set<int> mySet;
for(int i=0; i<N; i++) {
cin>>elem;
mySet.insert(GetFriendID(elem));
}
cout<<mySet.size()<<endl;
for(set<int>::iterator it=mySet.begin(); it!=mySet.end(); it++) {
if(it!=mySet.begin())
cout<<" ";
cout<<(*it);
}
return 0;
}
1121 Damn Single
一道简单的模拟题,用两个数组分别记录一个人是否在聚会中、一个人的另一个伴侣(伴侣:婚姻的另一半;若无伴侣则用-1表示)。题目中需要注意的情况是:
- 一对夫妻可能只有一个人参加了聚会,另一个人没来,那么这个参加了的人就是lonely的
- 输出格式中,编号必须是5位的格式,不足5位用0表示(测试点3)
- 若参加聚会的人中没有lonely的,在输出中不要多输出一个换行符(测试点1)
1122 Hamiltonian Cycle
给定一个无向图和若干路径,判断这些路径是否是汉密尔顿回路。这题不是很复杂。如何判断是否是汉密尔顿回路?
- 若图有N个结点,则回路的结点个数只能是N+1
- 路径首尾是相同的结点
- 回路有N个不同的结点(均是图对应的N个结点)
- 回路相邻结点必须在无向图中是联通的
1123 Is It a Complete AVL Tree
- 这道题就是考AVL树的基础操作,相关代码可以参考这篇博文,注意当树发生变化(如左旋、右旋、插入新结点)时,千万不要忘记调用updateHeight函数,否则结果会出错(细节有时候就容易忘记)
- 如何判断是否是完全二叉树:层次遍历中,若队列前N个元素中存在空节点,说明不是完全二叉树;反之则是。(代码可以参考下面)
void LevelOrder(TreeNode* root) {
queue<TreeNode*> myQueue;
int flag=0,num=0,flag2=1;
myQueue.push(root);
while(!myQueue.empty()) {
TreeNode* elem = myQueue.front();
myQueue.pop();
num++;
if(elem==NULL) {
if(num<=N) {
flag2=0;
}
continue;
}
if(flag==0)
flag=1;
else
cout<<" ";
cout<<elem->data;
myQueue.push(elem->left);
myQueue.push(elem->right);
}
if(flag2==1)
cout<<endl<<"YES"<<endl;
else
cout<<endl<<"NO"<<endl;
}
1124 Raffle for Weibo Followers
- 一道比较简单的模拟题,用一个变量标记下一个获奖者对应的indice
- 用set类型变量保存已获奖的人员,避免重复获奖
- 用queue保存获奖人员,以便按输入顺序输出他们的名字
1125 Chain the Ropes
题目大意:给N段绳子,要求把它们合并为一串,合并规则是:每次合并两个绳子,新绳子长度是原来两段绳子长度之和的一半。求最后得到的一串绳子,长度的最大值。
解题思路:
- 由题意知,越早参与合并的绳子,它为最终绳子长度的贡献权重就越低
- 所以应用贪心策略,让越长的绳子越迟参与合并、获得越大的贡献权重
- 类似哈夫曼树的求解过程
- 注意题目的精度问题,由于是向下取整操作,把每个绳子的长度取它的10倍保存,最后输出再除以10取整即可
#include <iostream>
#include <queue>
using namespace std;
int main() {
priority_queue<double,vector<double>,greater<double> > myQueue;
int N,elem;
cin>>N;
for(int i=0; i<N; i++) {
cin>>elem;
myQueue.push(elem*10);
}
while(myQueue.size()>1) {
double x = myQueue.top();
myQueue.pop();
double y = myQueue.top();
myQueue.pop();
myQueue.push((x+y)/2);
}
cout<<(int)myQueue.top()/10<<endl;
return 0;
}
1126 Eulerian Path
题目大意:给定一个无向图,求每个结点的度的大小,并判断该图的类型(有三个类型候选:Eulerian, semi-Eulerian, or non-Eulerian)
解题思路:
这题编程实现不难,关键在于第一段话的理论。很容易漏掉的信息是,“connected graphs”,编程的时候千万不要忘记连通图这个前提需要判断,可以用并查集算法实现连通图的判断。
- Eulerian:连通图+所有结点度数为偶数
- semi-Eulerian:连通图+有且仅有2个结点度数为奇数
- non-Eulerian:其他所有情况
#include <iostream>
using namespace std;
// 不要忽略连通图的条件限定,这个用并查集可以判断
const int MAXN=501;
int graph[MAXN][MAXN]= {0},father[MAXN];
void Init(int n) {
for(int i=0; i<=n; i++)
father[i] = i;
}
int Find(int x) {
if(x!=father[x])
father[x] = Find(father[x]); // 路径压缩
return father[x];
}
void Union(int x,int y) {
int fax = Find(x);
int fay = Find(y);
if(fax!=fay)
father[fax] = fay;
}
int main() {
int N,M,v1,v2,oddNum=0;
cin>>N>>M;
Init(N);
for(int i=0; i<M; i++) {
cin>>v1>>v2;
Union(v1,v2);
graph[v1][v2]=1;
graph[v2][v1]=1;
}
for(int i=1; i<=N; i++) {
int degree=0;
for(int j=1; j<=N; j++) {
if(i!=j)
degree+=graph[i][j];
}
if(i>1)
cout<<" ";
cout<<degree;
if(degree%2==1)
oddNum++;
}
int fa = Find(1);
for(int i=2; i<=N; i++) {
if(Find(i)!=fa) {
fa=-1;
break;
}
}
if(fa!=-1) {
if(oddNum==0)
cout<<endl<<"Eulerian"<<endl;
else if(oddNum==2)
cout<<endl<<"Semi-Eulerian"<<endl;
else
cout<<endl<<"Non-Eulerian"<<endl;
} else {
cout<<endl<<"Non-Eulerian"<<endl;
}
return 0;
}
1127 ZigZagging on a Tree
这道题是考二叉树遍历的基础题。给出二叉树的中序、后序遍历序列,求它的层序遍历序列(其中层序遍历的规则做了一点修改),解题关键步骤详见代码
void LevelTraverse(TreeNode* root) {
vector<int> myVec[MAXN]; // 记录每个层次有哪些结点(从左到右按顺序保存)
queue<TreeNode*> myQueue;
int maxLevel=1;
root->level=1;
myQueue.push(root);
while(!myQueue.empty()) {
TreeNode* elem = myQueue.front();
myQueue.pop();
int level = elem->level;
maxLevel = max(maxLevel,level);
myVec[level].push_back(elem->data);
if(elem->left!=NULL) {
elem->left->level = level+1;
myQueue.push(elem->left);
}
if(elem->right!=NULL) {
elem->right->level = level+1;
myQueue.push(elem->right);
}
}
cout<<myVec[1][0];
for(int i=2; i<=maxLevel; i++) {
if(i%2==0) {
for(int j=0; j<myVec[i].size(); j++) {
cout<<" "<<myVec[i][j];
}
} else {
for(int j=myVec[i].size()-1; j>=0; j--) {
cout<<" "<<myVec[i][j];
}
}
}
cout<<endl;
}
1128 N Queens Puzzle
就是一道八皇后的基础题,不是很难
1129 Recommendation System
一道中规中矩的模拟题
#include <iostream>
#include <queue>
using namespace std;
const int MAXN=5e4+10;
struct Item {
int label;
int num;
Item():num(0) {}
Item(int l):label(l),num(0) {}
Item(int l,int n):label(l),num(n) {}
bool operator< (const Item& y) const {
if(num!=y.num)
return num < y.num;
return label > y.label;
}
};
int kItem[11],epoch=0; // kItem仅记录榜单前K个物品有哪些,至于这K个物品的具体排名,交给Print函数中的优先队列来计算
int N,K;
int num[MAXN]= {0};
void Print(int newQuery) {
priority_queue<Item> myQueue; // 用于按照题目要求的规则进行输出
for(int i=0; i<epoch; i++) {
myQueue.push(Item(kItem[i],num[kItem[i]]));
}
cout<<newQuery<<":";
while(!myQueue.empty()) {
cout<<" "<<myQueue.top().label;
myQueue.pop();
}
cout<<endl;
}
void Fun(int newQuery) {
Print(newQuery);
num[newQuery]++;
int flag=0,minIndex=0; // minIndex用于记录kItem榜单中,最有可能被newQuery物品替换的物品的下标
for(int i=0; i<epoch; i++) {
int tmp1 = kItem[i],tmp2=kItem[minIndex];
if(num[tmp1]<num[tmp2] || (num[tmp1]==num[tmp2] && tmp1>tmp2))
minIndex = i;
if(tmp1==newQuery) { // 前K个物品中有 newQuery这个物品,无需更新kItem数组
flag=1;
break;
}
}
if(flag==0) { // 前K个物品中无 newQuery这个物品
if(epoch<K)
kItem[epoch++] = newQuery; // 更新kItem数组
else {
int tmp = kItem[minIndex];
if(num[newQuery]>num[tmp] || (num[newQuery]==num[tmp] && newQuery<tmp))
kItem[minIndex] = newQuery; // 更新kItem数组
}
}
}
int main() {
int query;
cin>>N>>K;
cin>>query;
num[query]++;
kItem[epoch++]=query;
for(int i=1; i<N; i++) {
cin>>query;
Fun(query);
}
return 0;
}
1130 Infix Expression
就是简单地考二叉树的中序遍历
#include <iostream>
using namespace std;
const int MAXN=21;
struct TreeNode {
string data;
int left;
int right;
TreeNode():data(""),left(-1),right(-1) {}
} tree[MAXN];
int vis[MAXN]= {0};
string GetExpression(int root) {
if(root==-1)
return "";
else {
string lpart=GetExpression(tree[root].left);
string rpart=GetExpression(tree[root].right);
string part = lpart + tree[root].data + rpart;
if((tree[root].left!=-1 || tree[root].right!=-1) && vis[root]!=0) {
part = "("+part+")";
}
return part;
}
}
int main() {
int N;
cin>>N;
for(int i=1; i<=N; i++) {
cin>>tree[i].data>>tree[i].left>>tree[i].right;
if(tree[i].left!=-1)
vis[tree[i].left]=1;
if(tree[i].right!=-1)
vis[tree[i].right]=1;
}
int root=1; // 寻找树的根结点
for(; root<=N; root++)
if(vis[root]==0)
break;
cout<<GetExpression(root)<<endl;
return 0;
}
1131 Subway Map
题目大意:
- 有N条铁路线路,每个线路经过若干站点;
- 两个站点若相邻,它们之间的通路只能在一条铁路线路上;地铁站点的编号范围在0000~9999之间;两条线路交叉的站点,称为换乘站点(transfer station),一个换乘站点最多连接5条线路;
- 有K个查询,对于每个查询,求出从出发站点到目的站点的最优路径;
- 最优路径的定义是:经过的站点数最少(第一标尺);换乘线路最少(第二标尺)。保证测试数据中,最优路径答案唯一。
解题思路:
- 就是一道最短路径的题目,用Dijkstra算法求解,其中每条边的权值均为1,这样可以获得第一标尺的值;
- 再用DFS算法,求第二标尺,获得最优路径;
- 在每条边,加个属性:所属路线,即可;
- 由于DFS递归得到的路线顺序恰好与原顺序相反,考虑到图是无向图,将出发站点与目的站点调换位置,不影响最终答案,且方便DFS求解最优路径
#include <iostream>
#include <vector>
#include <queue>
#include <climits>
#include <cstring>
using namespace std;
const int MAXN=1e4+1;
struct Edge {
int to;
int length;
int line; // 表示该边属于哪个地铁线路
Edge() {}
Edge(int _to,int _line):to(_to),length(1),line(_line) {}
};
struct Point {
int number;
int distance;
Point() {}
Point(int n,int d):number(n),distance(d) {}
};
vector<Edge> graph[MAXN];
int dis[MAXN],minTran=INT_MAX;
string resPath="";
vector<Edge> pre[MAXN];
string Tran(int x) {
if(x==0)
return "0";
string res="";
while(x>0) {
char temp = (x%10) + '0';
res = temp + res;
x/=10;
}
return res;
}
string Tran2(int x) {
if(x==0)
return "0000";
string res="";
while(x>0) {
char temp = (x%10) + '0';
res = temp + res;
x/=10;
}
int len = res.size();
for(int i=1; i<=4-len; i++)
res = "0"+res;
return res;
}
void Dijkstra(int s) {
dis[s]=0;
queue<Point> myQueue;
myQueue.push(Point(s,dis[s]));
while(!myQueue.empty()) {
int u = myQueue.front().number;
myQueue.pop();
for(int i=0; i<graph[u].size(); i++) {
int v = graph[u][i].to;
int d = graph[u][i].length;
int lineLable = graph[u][i].line;
if(dis[v]>dis[u]+d) {
pre[v].clear();
pre[v].push_back(Edge(u,lineLable));
dis[v]=dis[u]+d;
myQueue.push(Point(v,dis[v]));
} else if(dis[v]==dis[u]+d) {
pre[v].push_back(Edge(u,lineLable));
}
}
}
}
void DFS(int target,int cur,int transfer,int nowline,string path) {
if(target==cur) {
if(transfer<minTran) {
minTran = transfer;
resPath = path + Tran2(cur) + ".\n";
}
} else { // 此处的判断用于剪枝
for(int i=0; i<pre[cur].size(); i++) {
int t;
if(nowline==-1 || nowline==pre[cur][i].line)
t = transfer;
else
t = transfer + 1;
string p;
if(path=="") {
p = "Take Line#"+Tran(pre[cur][i].line)+" from "+Tran2(cur)+" to ";
} else {
p = path;
if(t==transfer+1) {
p = p + Tran2(cur) + ".\nTake Line#"+Tran(pre[cur][i].line)+" from "+Tran2(cur)+" to ";
}
}
DFS(target,pre[cur][i].to,t,pre[cur][i].line,p);
}
}
}
int main() {
int N,K,M,s1,s2;
memset(pre,0,sizeof(pre));
memset(graph,0,sizeof(graph));
cin>>N;
for(int i=1; i<=N; i++) {
cin>>M>>s1;
for(int j=1; j<M; j++) {
cin>>s2;
graph[s1].push_back(Edge(s2,i));
graph[s2].push_back(Edge(s1,i));
s1 = s2;
}
}
cin>>K;
for(int i=0; i<K; i++) {
cin>>s1>>s2;
memset(pre,0,sizeof(pre));
fill(dis,dis+MAXN,INT_MAX);
resPath="";
minTran=INT_MAX;
Dijkstra(s2);
DFS(s2,s1,0,-1,"");
cout<<dis[s1]<<endl<<resPath;
}
return 0;
}
1132 Cut Integer
#include <iostream>
using namespace std;
long long Tran(string x) {
long long res = 0,len = x.size();
for(int i=0; i<len; i++) {
res*=10;
res+=x[i]-'0';
}
return res;
}
int main() {
int N;
string str,a,b;
cin>>N;
for(int i=0; i<N; i++) {
cin>>str;
int len = str.size();
a = str.substr(0,len/2);
b = str.substr(len/2);
int elem1=Tran(str),elem2=(Tran(a)*Tran(b));
if(elem2!=0&&elem1%elem2==0)
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
return 0;
}
1133 Splitting A Linked List
题目大意:给一个含N个元素的链表和一个数K,需要进行一些操作,让负数排在非负数前面,让[0, K]区间的数排在大于K的数的前面,并且维持它们在原来链表中的顺序。
解题思路:
- 用静态链表的形式存储链表
- 将链表分成(负无穷, 0)、[0, K]、(K, 正无穷)三个区间来考虑,针对每个区间设置一个队列,用来维护链表每个元素的最初顺序(利用队列的先进先出的性质)
- 遍历链表,将将链表元素分别放入相应的队列
- 设置一定的输出规则,依次输出队列存放的值,即可得到对应的答案
#include <iostream>
#include <climits>
#include <cstdio>
#include <queue>
using namespace std;
const int MAXN=1e5+10;
int K;
struct Node {
int addr;
int data;
int next;
Node():addr(-1),data(INT_MAX),next(-1) {}
} nodes[MAXN];
int main() {
int head,N,addr;
cin>>head>>N>>K;
for(int i=1; i<=N; i++) {
cin>>addr;
cin>>nodes[addr].data>>nodes[addr].next;
nodes[addr].addr = addr;
}
queue<Node> left;
queue<Node> mid;
queue<Node> right;
int cur = head;
do {
if(nodes[cur].data<0)
left.push(nodes[cur]);
else if(nodes[cur].data<=K)
mid.push(nodes[cur]);
else
right.push(nodes[cur]);
cur = nodes[cur].next;
} while(cur!=-1);
int flag=0;
while(!left.empty()) {
Node u = left.front();
left.pop();
if(flag==0)
flag=1;
else
printf("%05d\n",u.addr);
printf("%05d %d ",u.addr,u.data);
}
while(!mid.empty()) {
Node u = mid.front();
mid.pop();
if(flag==0)
flag=1;
else
printf("%05d\n",u.addr);
printf("%05d %d ",u.addr,u.data);
}
while(!right.empty()) {
Node u = right.front();
right.pop();
if(flag==0)
flag=1;
else
printf("%05d\n",u.addr);
printf("%05d %d ",u.addr,u.data);
}
printf("-1\n");
return 0;
}
1134 Vertex Cover
题目大意:给定一个图,在给一个点集,若图的每条边至少有一个点是来自于这个点集,则称这个点集为Vertex Cover。
#include <iostream>
#include <vector>
#include <set>
using namespace std;
const int MAXN=1e4+10;
struct Edge {
int v1;
int v2;
Edge() {}
Edge(int _v1,int _v2):v1(_v1),v2(_v2) {}
};
int main() {
int N,M,K,v1,v2,num;
cin>>N>>M;
vector<Edge> myVector;
for(int i=0; i<M; i++) {
cin>>v1>>v2;
myVector.push_back(Edge(v1,v2));
}
cin>>K;
for(int i=0; i<K; i++) {
set<int> mySet;
cin>>num;
for(int i=0; i<num; i++) {
cin>>v2;
mySet.insert(v2);
}
int flag=1;
for(int j=0; j<M; j++) {
if(mySet.find(myVector[j].v1)==mySet.end()&&
mySet.find(myVector[j].v2)==mySet.end()) {
flag=0;
break;
}
}
if(flag==1)
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
return 0;
}
1135 Is It A Red-Black Tree(重要)
题目大意:给定一棵二叉查找树(即给出前序序列,中序序列是前序序列绝对值从小到大排序的结果;由前序、中序序列,确定唯一的一棵二叉查找树),判断它是否是一棵合法的红黑树。红黑树有如下五个性质:
- 每个结点不是红色就是黑色(本题中,用正的值表示黑色,用负的值表示红色)
- 根节点是黑色的
- 每一个叶子结点(即空结点)是黑色的
- 如果一个结点是红色的,它的孩子结点必须都是黑色的
- 从一个结点,到它的所有叶子结点的所有路径中,经过的黑结点的个数是相等的
解题思路:
本题首先要根据先序、中序序列,把对应的二叉树建立起来(这一步是传统操作,难度不大)。然后进行红黑树的判断:
- 性质1好判断,只要输入数据中不出现0,就不违背性质1。
- 性质2也好判断,只要树创建好后,对返回的根结点判断即可。
- 性质3不需要判断,它只是用来确定经过的黑色结点的个数
- 剩下的性质4和5,很明显需要递归遍历整棵树,具体判断的实现请看代码中的DFS函数
#include <iostream>
#include <algorithm>
#include <stack>
#include <queue>
using namespace std;
const int MAXN=50;
struct TreeNode {
int data;
int black; // 记录当前结点到根节点经过的黑色结点的个数
TreeNode* left; // 左孩子
TreeNode* right; // 右孩子
TreeNode(int d):data(d),left(NULL),right(NULL) {}
};
int PreOrder[MAXN],InOrder[MAXN];
TreeNode* Create(int prel,int prer,int inl,int inr) {
if(prel>prer)
return NULL;
else {
TreeNode* root = new TreeNode(PreOrder[prel]); // 先序序列第一个值对应树的根结点
int pos = inl; // pos把中序序列分成左右两部分
for(; pos<=inr; pos++) {
if(InOrder[pos]==abs(root->data))
break;
}
if(pos<=inr) { // 这里的判断一定要加上,不然会出现段错误
int leftLen = pos-inl; // 记录左子树有多少个结点
root->left = Create(prel+1,prel+leftLen,inl,pos-1);
root->right = Create(prel+leftLen+1,prer,pos+1,inr);
}
return root;
}
}
bool DFS(TreeNode* root) { // 用来获取每个结点到叶结点之间,路径上有多少黑色结点
if(root!=NULL) {
int ln,rn; // ln、rn分别表示左子树、右子树到达根结点经过的黑色结点个数
// 1. 先确定ln和rn的值
if(root->left==NULL)
ln=1;
else {
if(root->data<0 && root->left->data<0) // 表示出现了父子结点均为红色的情况,不满足红黑树的第4条性质
return false;
if(!DFS(root->left))
return false;
ln = root->left->black;
}
if(root->right==NULL)
rn=1;
else {
if(root->data<0 && root->right->data<0) // 表示出现了父子结点均为红色的情况,不满足红黑树的第4条性质
return false;
if(!DFS(root->right))
return false;
rn = root->right->black;
}
// 2. 判断ln和rn的值是否相等,若不等,则违背红黑树第5条性质
if(ln!=rn)
return false;
// 3. 更新根节点的black值
if(root->data>0)
root->black = ln + 1;
else
root->black = ln;
}
return true;
}
int main() {
int K,N;
cin>>K;
for(int i=0; i<K; i++) {
cin>>N;
int flag=1;
for(int j=0; j<N; j++) {
cin>>PreOrder[j];
InOrder[j]=abs(PreOrder[j]);
if(PreOrder[j]==0)
flag=0;
}
if(flag==0) { // 0无法确定结点是红色还是黑色,违背红黑树第1条性质
cout<<"No"<<endl;
continue;
}
sort(InOrder,InOrder+N);
TreeNode* root = Create(0,N-1,0,N-1);
if(root->data>0 && DFS(root)) // 根节点的值若不为正,则不是黑色,违背红黑树第2条性质
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
return 0;
}
1136 A Delayed Palindrome
就是一道基础的字符串操作题。
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
string Add(string x,string y) { // 这里两个字符串长度相同
string res="";
int carry=0;
for(int i=x.size()-1; i>=0; i--) {
carry+=(x[i]-'0')+(y[i]-'0');
char temp = carry%10+'0';
res = temp + res;
carry/=10;
}
while(carry>0) {
char temp = carry%10+'0';
res = temp + res;
carry/=10;
}
int pos = 0;
while(pos<res.size()&&res[pos]=='0')
pos++;
return res.substr(pos);
}
string Reverse(string x) {
reverse(x.begin(),x.end());
return x;
}
bool Jud(string x) {
return x==Reverse(x);
}
int main() {
string str,str1,str2,res="";
cin>>str;
int epoch=0;
while(Jud(str)==false && epoch<10) {
epoch++;
str1 = Reverse(str);
str2 = Add(str,str1);
res+=(str+" + "+str1+" = "+str2+"\n");
str = str2;
}
if(Jud(str))
cout<<res<<str<<" is a palindromic number."<<endl;
else
cout<<res<<"Not found in 10 iterations."<<endl;
return 0;
}
1137 Final Grading
一道简单的模拟题
#include <iostream>
#include <map>
#include <algorithm>
using namespace std;
const int MAXN=3e4+10;
struct Student {
string id;
int Gp;
int Gmid;
int Gfinal;
int G;
int qualified;
Student():Gp(-1),Gmid(-1),Gfinal(-1),G(-1) {}
void Calculate() {
if(Gp<200)
qualified=-1;
else {
if(Gmid<Gfinal)
G = Gfinal*10;
else
G = Gfinal*6 + Gmid*4;
if(G%10>4)
G+=10;
G/=10;
if(G<60)
qualified=-1;
else
qualified=1;
}
}
bool operator< (const Student& y) const {
if(qualified!=y.qualified)
return qualified > y.qualified;
if(G!=y.G)
return G > y.G;
return id < y.id;
}
} students[MAXN];
int main() {
map<string,int> myMap1;
int P,M,N,score,index=0;
string id;
cin>>P>>M>>N;
for(int i=0; i<P; i++) {
cin>>id>>score;
if(myMap1.find(id)==myMap1.end())
myMap1[id] = index++;
students[myMap1[id]].Gp = score;
students[myMap1[id]].id = id;
}
for(int i=0; i<M; i++) {
cin>>id>>score;
if(myMap1.find(id)==myMap1.end())
myMap1[id] = index++;
students[myMap1[id]].Gmid = score;
}
for(int i=0; i<N; i++) {
cin>>id>>score;
if(myMap1.find(id)==myMap1.end())
myMap1[id] = index++;
students[myMap1[id]].Gfinal = score;
}
for(int i=0; i<index; i++)
students[i].Calculate();
sort(students,students+index);
for(int i=0; i<index; i++) {
if(students[i].qualified==-1)
break;
cout<<students[i].id<<" "<<students[i].Gp<<" "<<students[i].Gmid<<" "<<students[i].Gfinal<<" "<<students[i].G<<endl;
}
return 0;
}
1138 Postorder Traversal
题目大意:给定先序、中序遍历序列,求后序序列的第一个元素
解题思路:
- 题目不需要求出整个后序序列,以往习惯做法是根据先序、中序建树,然后后序遍历得出结果。不过这题数据规模比较大,如果这样做的话,会超时的。
- 可以在建树的过程中,找到题目需要的答案,一旦找到,就停止建树过程,马上返回结果,这样就减少不必要的耗时。关键代码如下:
int flag=-1;
TreeNode* Create(int prel,int prer,int inl,int inr) {
if(flag==1 || prel>prer)
return NULL;
else {
TreeNode* root = new TreeNode(PreOrder[prel]);
if(prel==prer) {
flag=1;
cout<<root->data<<endl;
}
int pos=inl;
for(; pos<=inr; pos++) {
if(InOrder[pos]==root->data)
break;
}
int leftLen = pos-inl;
root->left = Create(prel+1,prel+leftLen,inl,pos-1);
root->right = Create(prel+leftLen+1,prer,pos+1,inr);
return root;
}
}
1139 First Contact(重要)
题目大意:给出好友关系图,再给出K对lovers。需要帮助每对lovers,寻找相应的好友,来间接(不那么直接地)传递他们的爱意。
解题思路:
- 这道题就是模拟+排序。
- 输入数据的处理方面很容易忽略-0000与0000的区别,解决办法详见代码。
- 寻找好友的过程可以用三重循环来实现。
- 用结构体的重载小于号函数+优先队列,可以实现多对好友的排序输出。
#include <iostream>
#include <vector>
#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
const int MAXN=1e4+10;
vector<int> graph[MAXN]; // 用邻接表存储好友关系
int gender[MAXN]= {0};
struct Pair { // 该结构体用于把结果按要求的格式和顺序输出,小于号的重载函数是主要的部分
int from;
int to;
Pair(int _from,int _to):from(_from),to(_to) {}
bool operator< (const Pair& y) const {
if(from!=y.from)
return from > y.from;
return to > y.to;
}
};
int Tran(string str) { // 将数字从字符串类型转换为int类型
if(str[0]=='-')
str = str.substr(1);
int res = 0;
for(int i=0; i<str.size(); i++) {
res*=10;
res+=(str[i]-'0');
}
return res;
}
int GetGender(string x) { // 获取对应的性别:-1表示女,1表示男
if(x[0]=='-')
return -1;
return 1;
}
void setEdge(int x,int y) { // 将好友关系更新到邻接表中
graph[x].push_back(y);
graph[y].push_back(x);
}
void Calculate(int a,int b) {
if(gender[a]==0 || gender[b]==0) { // a和b至少有一个不存在于好友关系表graph中
cout<<0<<endl;
return ;
}
priority_queue<Pair> res; // 用优先队列,配合结构体的小于号重载函数,能实现自动排序的功能,从而控制输出的格式
for(int i=0; i<graph[a].size(); i++) { // 该三重循环函数,就是寻找合适好友的关键代码
int u = graph[a][i];
if(u!=a && u!=b && gender[u]==gender[a]) {
for(int j=0; j<graph[u].size(); j++) {
int v = graph[u][j];
if(v!=a && v!=b && gender[v]==gender[b]) {
for(int k=0; k<graph[v].size(); k++) {
if(graph[v][k]==b)
res.push(Pair(u,v));
}
}
}
}
}
// 以下是结果的输出
cout<<res.size()<<endl;
while(!res.empty()) {
Pair x = res.top();
res.pop();
printf("%04d %04d\n",x.from,x.to);
}
}
int main() {
int N,M,K;
cin>>N>>M;
for(int m=0; m<M; m++) {
string str1,str2; // 增加了string到int的转换流程,就是为了发现-0000与0000这个边界情况!!!!!
int v1,v2;
cin>>str1>>str2;
v1 = Tran(str1);
v2 = Tran(str2);
gender[v1] = GetGender(str1);
gender[v2] = GetGender(str2);
setEdge(v1,v2);
}
cin>>K;
for(int k=0; k<K; k++) {
int a,b;
cin>>a>>b;
Calculate(abs(a),abs(b)); // 以上都是数据保存过程中的处理,代码核心功能在这个函数
}
return 0;
}
1140 Look-and-say Sequence
一道规律发现题,思路详见代码
#include <iostream>
using namespace std;
string Tran(int x) { // 将数字转换为对应的字符串形式
if(x==0)
return "0";
string res="";
while(x>0) {
char temp = (x%10) + '0';
res = temp + res;
x/=10;
}
return res;
}
string GenerateNext(string old) {
string res = "";
int len = old.size();
for(int i=0; i<len;) {
int pre=i;
while(i<len&&old[i]==old[pre])
i++;
res+=old[pre]+Tran(i-pre); // 每遇到一个新字符,就记录它的值、记录它连续的个数,拼接到新的字符串中
}
return res;
}
int main() {
int D,N;
cin>>D>>N;
string res = Tran(D);
for(int i=1; i<N; i++)
res = GenerateNext(res);
cout<<res<<endl;
return 0;
}
1141 PAT Ranking of Institutions
题目大意:给出一组来自不同学校的学生的考试成绩,求各个学校的排名。
解题思路:
- 设计好学校结构体的属性和函数(先用sa sb st三个变量保存三个不同考试级别的分数总和;再设计函数GetTWS(),计算TWS,保留整数部分而不是四舍五入)
- 处理输入数据:学生的学号不用保存,它只是用来判断学生所得到的成绩对应哪一个级别的考试;学生归属的学校的名字,要用函数ToLower()来处理,这个函数可以记下来,以后需要的时候直接用,还是比较好用的
- 计算每个学校的TWS结果
- 根据题目的排序规则设计好Institution结构体的小于号重载函数,然后调用sort函数
- 输出排名结果:注意一下rank的取值规则即可
#include <iostream>
#include <string>
#include <algorithm>
#include <map>
using namespace std;
const int MAXN=1e5+10;
struct Institution {
string school;
int sa;
int sb;
int st;
int TWS;
int stuNum;
Institution():sa(0),sb(0),st(0),stuNum(0) {}
void GetTWS() {
double res = sa;
res+=sb/1.50+st*1.5;
TWS=res;
}
bool operator< (const Institution& y) const {
if(TWS!=y.TWS)
return TWS > y.TWS;
if(stuNum!=y.stuNum)
return stuNum<y.stuNum;
return school < y.school;
}
} institution[MAXN];
map<string,int> ID2num;
map<int,string> num2ID;
string ToLower(string x) {
transform(x.begin(),x.end(),x.begin(),::tolower);
return x;
}
int main() {
int N,score;
string ID,SchoolName;
cin>>N;
for(int i=0; i<N; i++) {
cin>>ID>>score>>SchoolName;
SchoolName = ToLower(SchoolName);
if(ID2num.find(SchoolName)==ID2num.end()) {
int len = ID2num.size();
ID2num[SchoolName]=len;
}
institution[ID2num[SchoolName]].school = SchoolName;
institution[ID2num[SchoolName]].stuNum++;
if(ID[0]=='A')
institution[ID2num[SchoolName]].sa+=score;
else if(ID[0]=='B')
institution[ID2num[SchoolName]].sb+=score;
else if(ID[0]=='T')
institution[ID2num[SchoolName]].st+=score;
}
int length = ID2num.size(),rankPre=1;
for(int i=0; i<length; i++)
institution[i].GetTWS();
sort(institution,institution+length);
cout<<length<<endl;
for(int i=0; i<length; i++) {
Institution elem = institution[i];
if(!(i==0 || elem.TWS==institution[i-1].TWS))
rankPre = i+1;
cout<<rankPre<<" "<<elem.school<<" "<<elem.TWS<<" "<<elem.stuNum<<endl;
}
return 0;
}
1142 Maximal Clique(不知道为什么这题代码一直未通过一个测试点)
题目大意:
- 给出一个无向图,在给出K个点集。
- 为每个点集,判断集合中每个点是否两两都是直接相连的,如果是,则是一个Clique;反之则不是。
- 若是一个Clique,则再判断“是否能往集合中添加一个点,该点与集合中其他点均直接相连”,如果能,则不是一个max Clique;反之则是。
解题思路:(详见代码,不是很难)
这篇博文的代码是通过了测试的。下面的代码是我自己写的,没通过测试。我比对了半天,没找出我代码的bug,太难受了,堵心。
#include <iostream>
using namespace std;
const int MAXN=201;
int graph[MAXN][MAXN]= {0};
int temp[MAXN]; // 记录待判断的子图
int vis[MAXN]= {0}; // 记录哪些结点被包含在子图中
int N,Ne,M,K;
int main() {
int x, y;
cin>>N>>Ne;
for(int i=0; i<Ne; i++) {
cin>>x>>y;
graph[x][y]=1;
graph[y][x]=1;
}
cin>>M;
for(int query=1; query<=M; query++) {
cin>>K;
fill(vis,vis+N,0);
for(int i=0; i<K; i++)
cin>>temp[i],vis[temp[i]]=1;
int flag=1;
for(int i=0; i<K; i++) {
for(int j=i+1; j<K&&flag==1; j++) {
if(graph[temp[i]][temp[j]]==0) { // 存在不连通的情况
flag=0;
break;
}
}
}
if(flag==0) {
cout<<"Not a Clique"<<endl;
} else {
int jud=1;
for(int i=1; i<=N; i++) {
if(vis[i]==0) {
for(int j=0; j<K; j++) {
if(graph[temp[j]][i]==0) { // 存在不连通的情况
break;
}
if(j==K-1) {
jud=0;
}
}
if(jud==0) {
cout<<"Not Maximal"<<endl;
break;
}
}
}
if(jud==1)
cout<<"Yes"<<endl;
}
}
return 0;
}
1143 Lowest Common Ancestor
题目大意:给定一棵二叉搜索树,再给两个结点值,查询这两个结点的最近公共祖先。
解题思路:
- 先根据题目给出的先序遍历序列,计算中序遍历序列(即先序序列从小到大排序的结果),然后根据这两个序列,创建对应的二叉搜索树。
- 然后利用DFS函数分别获得两个结点的路径,若结点不在树中,DFS函数返回false。
- 然后根据这两个路径,用if...else分支结构判断各种可能的情况并输出对应格式的结果。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int MAXN=1e4+10;
struct TreeNode {
int data;
TreeNode* left;
TreeNode* right;
TreeNode():left(NULL),right(NULL) {}
TreeNode(int d):data(d),left(NULL),right(NULL) {}
};
int PreOrder[MAXN],InOrder[MAXN];
TreeNode* Create(int prel,int prer,int inl,int inr) {
if(prel>prer)
return NULL;
else {
TreeNode* root = new TreeNode(PreOrder[prel]);
int pos = inl;
for(; pos<=inr; pos++) {
if(InOrder[pos]==root->data)
break;
}
int leftLen = pos-inl;
root->left = Create(prel+1,prel+leftLen,inl,pos-1);
root->right = Create(prel+leftLen+1,prer,pos+1,inr);
return root;
}
}
bool DFS(TreeNode* root,int val,vector<int>& path) {
if(root==NULL)
return false;
path.push_back(root->data);
if(root->data == val)
return true;
else if(root->data < val)
return DFS(root->right,val,path);
else if(root->data > val)
return DFS(root->left,val,path);
}
void Calculate(TreeNode* root,int u,int v) {
vector<int> upath;
vector<int> vpath;
bool judu = DFS(root,u,upath);
bool judv = DFS(root,v,vpath);
if(judu==false && judv==false)
cout<<"ERROR: "<<u<<" and "<<v<<" are not found."<<endl;
else if(judu==false)
cout<<"ERROR: "<<u<<" is not found."<<endl;
else if(judv==false)
cout<<"ERROR: "<<v<<" is not found."<<endl;
else {
int lenu = upath.size();
int lenv = vpath.size();
int pos=0;
for(; pos<lenu&&pos<lenv; pos++) {
if(upath[pos]!=vpath[pos])
break;
}
if(pos==lenu)
cout<<u<<" is an ancestor of "<<v<<"."<<endl;
else if(pos==lenv)
cout<<v<<" is an ancestor of "<<u<<"."<<endl;
else
cout<<"LCA of "<<u<<" and "<<v<<" is "<<upath[pos-1]<<"."<<endl;
}
}
int main() {
int M,N,u,v;
cin>>M>>N;
for(int i=0; i<N; i++) {
cin>>PreOrder[i];
InOrder[i] = PreOrder[i];
}
sort(InOrder,InOrder+N);
TreeNode* root = Create(0,N-1,0,N-1);
for(int m=0; m<M; m++) {
cin>>u>>v;
Calculate(root,u,v);
}
return 0;
}
1144 The Missing Number
题目大意:给出N个int范围内的整数列表(可正可负),求最小的正整数,且该正整数不在列表中
解题思路:详见代码
其他:
PAT上的测试,可能有个没考虑到:
10
7 7 7 7 6 5 4 3 2 1
#include <iostream>
#include <queue>
using namespace std;
int main() {
int N,elem;
priority_queue<int,vector<int>,greater<int> > myQueue; // 将列表正整数从小到大排列
cin>>N;
for(int i=0; i<N; i++) {
cin>>elem;
if(elem>0) // 解题中,我们只需要关心正整数
myQueue.push(elem);
}
int flag=0;
int index=1; // index表示当前队列未遍历到的最小正整数
while(!myQueue.empty()) {
if(myQueue.top()>index) { // 队列不存在index
flag=1;
cout<<index<<endl;
break;
} else if(myQueue.top()==index) // 此处若myQueue.top()<index,说明队首元素之前已经出现过了,index因而不做任何处理
index++;
myQueue.pop();
}
if(flag==0) // 出现这种情况说明,myQueue中的元素均能完整覆盖区间[1, index-1]
cout<<index; // 如果这里输出myQueue.size()的值,题目好像不会检测出错误,但是它是一个错误
return 0;
}
1145 Hashing - Average Search Time(考点在hash)
题目大意:将N个数插入到一个给定大小的hash表中(用正向平方探测法处理冲突)。在给出M个数,查询这M个数是否在hash表格中存在,求这M个数的平均查询次数。
解题思路:
- 平方探测法的使用。在平方探测法中,为了尽可能避免扎堆现象,当表中下标为H(key)的位置被占时,将按下面的顺序检查表中的位置:H(key)+1^2、H(key)+2^2、H(key)+3^2......如果检查过程中H(key)+k^2超过了表长TSize,那么就对其取模(模数为TSize)。如果k在[0,TSize)范围内都无法找到地址,那么当k>=TSize时也肯定无法找到,因此只需遍历k从[0, TSize-1]即可。
- 查询操作。查询当前数在hash表中所在位置或是计算查询次数,均需要再次模拟插入过程,当找到这个数,或者发现这个位置上没有数(即值为-1)时,表示已经找到这个数或者无此数,无需继续查询。
#include <iostream>
#include <cstdio>
using namespace std;
const int MAXN=1e4+10;
int TSize,MSize,N,M;
int Hash[MAXN];
void Init() { // 确定hash表格的大小
for(int i=MSize; i<MAXN; i++) {
int flag=1;
for(int j=2; j*j<=i && flag==1; j++)
if(i%j==0)
flag=0;
if(flag==1) {
TSize = i;
break;
}
}
fill(Hash,Hash+TSize+1,-1);
}
void SetHashKey(int key) {
int pos = key%TSize,flag=0;
for(int i=0; i<TSize; i++) { // 二次探测的边界在区间[0,TSize-1]
if(Hash[(i*i+pos)%TSize]==-1) {
Hash[(i*i+pos)%TSize] = key;
flag=1;
break;
}
}
if(flag==0)
cout<<key<<" cannot be inserted."<<endl;
}
int GetSearchTime(int val) {
int i,res=0,pos = val%TSize;
for(i=0; i<=TSize; i++) {
res++; // 比较次数加1
if(Hash[(i*i+pos)%TSize]==-1 || Hash[(i*i+pos)%TSize]==val)
break;
}
return res;
}
int main() {
cin>>MSize>>N>>M;
Init();
for(int i=0; i<N; i++) {
int elem;
cin>>elem;
SetHashKey(elem);
}
int sum=0;
for(int m=0; m<M; m++) {
int elem;
cin>>elem;
sum+=GetSearchTime(elem);
}
printf("%.1lf\n",sum*1.0/M);
return 0;
}
1146 Topological Order
题目大意:给定一个有向图,给出K个序列,判断其中哪些序列是该图的拓扑路径。
解题思路:判断是否是拓扑路径,只需按着给出的路径走,对每个点执行以下操作:
- 该点入度是否为0?若为0,则执行后续操作;若不为0,则不是拓扑路径,算法结束判断。
- 遍历该点的所有出边,将每条边对应的另一端点的入度减1。
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
const int MAXN=1e3+10;
vector<int> graph[MAXN];
int inDegree[MAXN];
int tmpDegree[MAXN],tmpTopo[MAXN];
bool Jud(int n) {
for(int i=1; i<=n; i++)
tmpDegree[i] = inDegree[i];
for(int i=1; i<=n; i++) {
int u = tmpTopo[i];
if(tmpDegree[u]!=0)
return false;
for(int j=0; j<graph[u].size(); j++) {
int v = graph[u][j];
tmpDegree[v]--;
}
}
return true;
}
int main() {
int N,M,K;
cin>>N>>M;
for(int i=0; i<M; i++) {
int v1,v2;
cin>>v1>>v2;
graph[v1].push_back(v2);
inDegree[v2]++;
}
cin>>K;
int printFlag=0;
for(int k=0; k<K; k++) {
for(int i=1; i<=N; i++)
cin>>tmpTopo[i];
if(!Jud(N)) {
if(printFlag==0)
printFlag=1;
else
cout<<" ";
cout<<k;
}
}
cout<<endl;
return 0;
}
1147 Heaps
题目大意:给定一个完全二叉树的层序遍历序列,判断它是否是一个大顶堆或者是一个小顶堆,或者不是一个堆,并输出该树的后序遍历序列。
解题思路:
完全二叉树可以直接用数组来存储,因为第i个结点的左、右孩子分别是第i*2、i*2+1个结点。
具体思路详见代码
#include <iostream>
using namespace std;
const int MAXN=1e4+10;
int tree[MAXN],postFlag;
void PostTraverse(int cur,int n) {
if(cur<=n) {
PostTraverse(cur*2,n);
PostTraverse(cur*2+1,n);
if(postFlag==0)
postFlag=1;
else
cout<<" ";
cout<<tree[cur];
}
}
int main() {
int M,N;
cin>>M>>N;
for(int m=0; m<M; m++) {
int flag=0; // 0 表示父子结点目前的值是相等的,1表示小顶堆,2表示大顶堆,-1表示不是堆
for(int n=1; n<=N; n++) {
cin>>tree[n];
if(flag==-1)
continue;
if(n>1) {
if(tree[n/2]>tree[n]) { // 可能是大顶堆
if(flag==0)
flag=2;
else if(flag==1)
flag=-1;
} else if(tree[n/2]<tree[n]) { // 可能是小顶堆
if(flag==0)
flag=1;
else if(flag==2)
flag=-1;
}
}
}
if(flag==-1)
cout<<"Not Heap"<<endl;
else if(flag==1)
cout<<"Min Heap"<<endl;
else if(flag==2)
cout<<"Max Heap"<<endl;
postFlag=0;
PostTraverse(1,N);
cout<<endl;
}
return 0;
}
1148 Werewolf - Simple Version
题目大意:在狼人杀游戏中,有N个玩家,玩家分为人类、狼两大阵营,其中有且仅有2只狼。N个玩家每人分别叙述一条信息,其中有且仅有2个玩家说谎(一个是狼,一个是人类)。任务:找出2只狼。
解题思路:
- 题目的N规模仅为100,不是很大,可以对N个玩家按照递增顺序枚举所有是狼的可能组合(复杂度为O(n^2))
- 然后对每个组合判断说谎者的个数
- 若个数为2,且说谎者是一个人类和一只狼,则该组合就是答案,输出结果,程序结束,不再进行后续判断
- 反之,该组合不是答案,继续枚举下一个组合
- 若遍历完所有组合,仍然没有找到答案,则输出"No Solution"
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN=101;
int N;
int desc[MAXN];
bool solve(int p1,int p2) {
vector<int> liars;
for(int i=1; i<=N; i++) {
if((desc[i]<0 && abs(desc[i])!=p1 && abs(desc[i])!=p2)||
(desc[i]>0 && (desc[i]==p1 || desc[i]==p2))) { // 当前玩家在说谎
liars.push_back(i);
}
if(liars.size()>2)
return false;
}
if(liars.size()==2) { // 要记得判断:说谎者必须1个是狼,1个是人
if((liars[0]==p1||liars[0]==p2)&&liars[1]!=p1&&liars[1]!=p2)
return true;
if((liars[1]==p1||liars[1]==p2)&&liars[0]!=p1&&liars[0]!=p2)
return true;
}
return false;
}
int main() {
cin>>N;
for(int i=1; i<=N; i++)
cin>>desc[i];
int flag=0;
for(int i=1; i<N&&flag==0; i++) {
for(int j=i+1; j<=N; j++) {
if(solve(i,j)==true) {
flag=1;
cout<<i<<" "<<j<<endl;
break;
}
}
}
if(flag==0) {
cout<<"No Solution"<<endl;
}
return 0;
}
1149 Dangerous Goods Packaging
题目大意:给出N对不兼容的物品,在给出K个物品清单。对每个清单,判断它的所有物品是否可以兼容地放在一个容器中。
解题思路:用set记录每个物品不兼容的其他物品的集合(incompa数组可以类比vector<int> graph[MAXN],只不过我们不需要关心具体下标,只要元素存在于集合中就好,所以用set代替vector)
#include <iostream>
#include <set>
using namespace std;
const int MAXN=1e5+10;
set<int> incompa[MAXN];
int arr[1001];
int main() {
int N,M,K,v1,v2;
cin>>N>>M;
for(int i=0; i<N; i++) {
cin>>v1>>v2;
incompa[v1].insert(v2);
incompa[v2].insert(v1);
}
for(int m=0; m<M; m++) {
int flag=1;
cin>>K;
for(int k=0; k<K; k++) {
cin>>arr[k];
for(int i=0; i<k&& flag==1; i++) {
if(incompa[arr[k]].find(arr[i])!=incompa[arr[k]].end()) {
flag=0;
}
}
}
if(flag==1)
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
return 0;
}
1150 Travelling Salesman Problem
题目大意:给定一个无向图,再给出K个路径,对每个路径:求出长度,并判断是否经过图中所有点并形成环路。
解题思路:比较简单,详见代码
#include <iostream>
#include <vector>
#include <set>
using namespace std;
const int MAXN=201;
int graph[MAXN][MAXN]= {0};
int resk=-1,resdis=-1,N;
void Calculate(int knum,vector<int> path) {
set<int> vis;
int totalDis=0,len=path.size();
for(int i=len-1; i>0; i--) {
int u = path[i],v = path[i-1];
if(graph[u][v]!=0) {
totalDis+=graph[u][v];
vis.insert(u);
vis.insert(v);
} else {
cout<<"Path "<<knum<<": NA (Not a TS cycle)"<<endl;
return ;
}
}
string str;
if(vis.size()==N && path[0]==path[len-1]) {
if(len==N+1)
str=" (TS simple cycle)";
else
str=" (TS cycle)";
if(resdis==-1 || totalDis<resdis) {
resdis = totalDis;
resk = knum;
}
} else {
str=" (Not a TS cycle)";
}
cout<<"Path "<<knum<<": "<<totalDis<<str<<endl;
}
int main() {
int M,K,c1,c2,dis;
cin>>N>>M;
for(int m=0; m<M; m++) {
cin>>c1>>c2>>dis;
graph[c1][c2]=dis;
graph[c2][c1]=dis;
}
cin>>K;
for(int k=1; k<=K; k++) {
vector<int> p;
int elem,n;
cin>>n;
for(int i=0; i<n; i++) {
cin>>elem;
p.push_back(elem);
}
Calculate(k,p);
}
cout<<"Shortest Dist("<<resk<<") = "<<resdis<<endl;
return 0;
}
1151 LCA in a Binary Tree
题目大意:给定一颗二叉树的中序、前序序列,求两个结点的最近祖先。
解题思路:
- 根据中序、前序序列,创建对应的二叉树
- 用一个set类型实例(treeKeys)记录树中包含的结点,用于判断待查询的结点是否在树中存在(在复杂度方面,用空间换时间)
- 若待查询的一对结点均存在于树中,则求它们的最近祖先
#include <iostream>
#include <vector>
#include <set>
using namespace std;
const int MAXN=10001;
struct TreeNode {
int data;
TreeNode* left;
TreeNode* right;
TreeNode():left(NULL),right(NULL) {}
TreeNode(int _data):data(_data),left(NULL),right(NULL) {}
};
int InOrder[MAXN],PreOrder[MAXN],tmpLevel,isFind,level1,level2;
int seq1[MAXN],seq2[MAXN];
set<int> treeKeys; // 该集合用于判断待查询的key是否在树中
TreeNode* Create(int prel,int prer,int inl,int inr) { // 前序、中序序列可以唯一地确定一颗树
if(prel>prer)
return NULL;
TreeNode* root = new TreeNode(PreOrder[prel]);
int pos = inl;
for(; pos<=inr; pos++) {
if(InOrder[pos]==root->data)
break;
}
int leftLen = pos-inl;
root->left = Create(prel+1,prel+leftLen,inl,pos-1);
root->right = Create(prel+leftLen+1,prer,pos+1,inr);
return root;
}
void Find(TreeNode* root,int val,int level,int* seq) {
if(root!=NULL&&isFind==0) { // 剪枝操作,若已找到目标结点,则结束后面的递归
seq[level]=root->data;
if(root->data!=val) {
Find(root->left,val,level+1,seq);
Find(root->right,val,level+1,seq);
} else { // 找到值为val的目标结点
tmpLevel=level;
isFind=1;
}
}
}
void LCA(int e1,int e2) {
int pos=0;
while(pos<=level1&&pos<=level2&&seq1[pos]==seq2[pos]) {
pos++;
}
if(seq1[pos-1]==e1)
cout<<e1<<" is an ancestor of "<<e2<<"."<<endl;
else if(seq2[pos-1]==e2)
cout<<e2<<" is an ancestor of "<<e1<<"."<<endl;
else
cout<<"LCA of "<<e1<<" and "<<e2<<" is "<<seq1[pos-1]<<"."<<endl;
}
int main() {
int M,N;
cin>>M>>N;
for(int i=1; i<=N; i++) {
cin>>InOrder[i];
treeKeys.insert(InOrder[i]);
}
for(int i=1; i<=N; i++)
cin>>PreOrder[i];
TreeNode* root = Create(1,N,1,N);
for(int m=1; m<=M; m++) {
int e1,e2;
cin>>e1>>e2;
if(treeKeys.count(e1)==0&&treeKeys.count(e2)==0)
cout<<"ERROR: "<<e1<<" and "<<e2<<" are not found."<<endl;
else if(treeKeys.count(e1)==0)
cout<<"ERROR: "<<e1<<" is not found."<<endl;
else if(treeKeys.count(e2)==0)
cout<<"ERROR: "<<e2<<" is not found."<<endl;
else {
isFind=0;
Find(root,e1,0,seq1);
level1=tmpLevel;
isFind=0;
Find(root,e2,0,seq2);
level2=tmpLevel;
LCA(e1,e2);
}
}
return 0;
}
1152 Google Recruitment
题目大意:在含L个数字的连续序列中,寻找第一个出现的子连续序列,使得该子连续序列长度为K、且组成的数是一个素数。
解题思路:题目比较简单,见代码。
#include <iostream>
using namespace std;
int L,K;
bool isPrime(int x) {
// 判断素数的时候要把0和1也考虑进去
if(x==0 || x==1)
return false;
for(int i=2; i*i<=x; i++) {
if(x%i==0)
return false;
}
return true;
}
int Tran(string x) {
int carry=0,len=x.size();
for(int i=0; i<len; i++) {
carry*=10;
carry+=(x[i]-'0');
}
return carry;
}
int main() {
int flag=0;
string str;
cin>>L>>K>>str;
for(int i=0; i+K<=L; i++) { // 这里的等号也要取到
if(isPrime(Tran(str.substr(i,K)))==true) {
cout<<str.substr(i,K)<<endl;
flag=1;
break;
}
}
if(flag==0)
cout<<404<<endl;
return 0;
}
1153 Decode Registration Card of PAT(这题目自己暂时还未解决超时的问题)
这篇博文写的很好
#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
#include <unordered_map>
#include <string>
#include <set>
using namespace std;
const int MAXN=1e4+1;
struct Type1 {
string CardNum;
int score;
Type1() {}
Type1(string _CardNum,int _score):CardNum(_CardNum),score(_score) {}
bool operator< (const Type1& y) const {
if(score!=y.score)
return score > y.score;
return CardNum < y.CardNum;
}
};
struct Type2 {
set<string> Nt;
int Ns;
Type2():Ns(0) {}
};
struct Type3 {
string site;
set<string> Nt;
Type3() {}
Type3(string _site, set<string> nt):site(_site),Nt(nt) {}
bool operator< (const Type3& y) const {
if(Nt.size()!=y.Nt.size())
return Nt.size() > y.Nt.size();
return site < y.site;
}
};
vector<Type1> LT,LA,LB;
map<string,Type2> SITE;
unordered_map<string,unordered_map<string,set<string> > > DATE;
void AddType1(string card,int score) {
if(card[0]=='T')
LT.push_back(Type1(card,score));
else if(card[0]=='A')
LA.push_back(Type1(card,score));
else if(card[0]=='B')
LB.push_back(Type1(card,score));
}
void SortType1() {
sort(LT.begin(),LT.end());
sort(LA.begin(),LA.end());
sort(LB.begin(),LB.end());
}
void GetType1(string level) {
vector<Type1> seq;
if(level[0]=='T')
seq = LT;
else if(level[0]=='A')
seq = LA;
else if(level[0]=='B')
seq = LB;
int len = seq.size();
if(len==0)
cout<<"NA"<<endl;
else {
for(int i=0; i<len; i++)
cout<<seq[i].CardNum<<" "<<seq[i].score<<endl;
}
}
void AddType2(string card,int score) {
string site = card.substr(1,3);
SITE[site].Ns+=score;
SITE[site].Nt.insert(card.substr(10,3));
}
void GetType2(string site) {
if(SITE.count(site)==0)
cout<<"NA"<<endl;
else
cout<<SITE[site].Nt.size()<<" "<<SITE[site].Ns<<endl;
}
void AddType3(string card,int score) {
string date = card.substr(4,6);
string site = card.substr(1,3);
DATE[date][site].insert(card.substr(10,3));
}
void GetType3(string date) {
vector<Type3> res;
unordered_map<string,set<string> > dateElem = DATE[date];
if(dateElem.size()==0)
cout<<"NA"<<endl;
else {
unordered_map<string,set<string> >::iterator it=dateElem.begin();
for(; it!=dateElem.end(); it++) {
res.push_back(Type3(it->first,it->second));
}
sort(res.begin(),res.end());
int len = res.size();
for(int i=0; i<len; i++)
cout<<res[i].site<<" "<<res[i].Nt.size()<<endl;
}
}
int main() {
int N,M,score,type;
string CardNum,term;
cin>>N>>M;
for(int n=1; n<=N; n++) {
cin>>CardNum>>score;
AddType1(CardNum,score);
AddType2(CardNum,score);
AddType3(CardNum,score);
}
SortType1();
for(int m=1; m<=M; m++) {
cin>>type>>term;
cout<<"Case "<<m<<": "<<type<<" "<<term<<endl;
if(type==1)
GetType1(term);
else if(type==2)
GetType2(term);
else if(type==3)
GetType3(term);
}
return 0;
}
1154 Vertex Coloring
一道模拟题,不是很难
#include <iostream>
#include <set>
#include <vector>
using namespace std;
const int MAXN=1e4+10;
int N,M,color[MAXN];
struct Edge {
int v1;
int v2;
Edge() {}
Edge(int _v1,int _v2):v1(_v1),v2(_v2) {}
};
vector<Edge> myEdge;
set<int> ColorKinds;
void Calculate() {
int len = myEdge.size(),flag=1;
for(int i=0; i<len&&flag==1; i++) {
int v1=myEdge[i].v1,v2=myEdge[i].v2;
if(color[v1]==color[v2])
flag=0;
}
if(flag==0)
cout<<"No"<<endl;
else
cout<<ColorKinds.size()<<"-coloring"<<endl;
}
int main() {
cin>>N>>M;
for(int m=0; m<M; m++) {
int v1,v2;
cin>>v1>>v2;
myEdge.push_back(Edge(v1,v2));
}
int K;
cin>>K;
for(int k=0; k<K; k++) {
ColorKinds.clear();
for(int i=0; i<N; i++) {
cin>>color[i];
ColorKinds.insert(color[i]);
}
Calculate();
}
return 0;
}
1155 Heap Paths
题目大意:给出一棵完全二叉树的层序遍历序列,判断它是否是小顶堆或大顶堆,并按照右子树优先的顺序输出所有从根结点到叶结点的路径。
解题思路:DFS+字符串处理+完全二叉树的考点,详情见代码
#include <iostream>
#include <set>
#include <sstream>
using namespace std;
const int MAXN=2e3+10;
int tree[MAXN],N;
set<string> resPath;
string Tran(int x) {
stringstream ss;
ss<<x;
string res;
ss>>res;
return res;
/* 下面这种写法存在bug,以后不要采用这样的方式了
if(x==0)
return "0";
string res="";
while(x>0) {
char temp = (x%10) + '0';
res = temp + res;
x/=10;
}
return res;
*/
}
void DFS(int root,string path) {
if(root*2>N) {
if(root<=N && resPath.find(path)==resPath.end()) { //root<=N的条件限制不要忘记
cout<<path<<endl;
resPath.insert(path);
}
} else {
DFS(root*2+1,path+" "+Tran(tree[root*2+1]));
DFS(root*2,path+" "+Tran(tree[root*2]));
}
}
int main() {
cin>>N;
int flag=0; // 0表示未出现父子结点值不相同的情况,1表示小顶堆,2表示大顶堆,-1表示不是堆
for(int i=1; i<=N; i++) {
cin>>tree[i];
if(flag==-1)
continue;
if(i>1) {
if(tree[i/2] < tree[i]) {
if(flag==0)
flag=1;
else if(flag==2)
flag=-1;
} else if(tree[i/2] > tree[i]) {
if(flag==0)
flag=2;
else if(flag==1)
flag=-1;
}
}
}
DFS(1,Tran(tree[1]));
if(flag==1)
cout<<"Min Heap"<<endl;
else if(flag==2)
cout<<"Max Heap"<<endl;
else if(flag==-1)
cout<<"Not Heap"<<endl;
return 0;
}