感觉就是在赎大学三年没好好练习算法的罪孽
本次作业涉及到的知识点有:
题号 | 难度 | 知识点 |
---|---|---|
1140 | 字符串和数字的转化+英语阅读理解 | |
1141 | STL+排序(涉及基础的字符串处理) | |
1142 | 图论(图基础的基础的基础,没啥知识点几乎) | |
1143 | BST树的搜索与建立+时间复杂度优化最怕有思路但是卡时间的题目了(这题如果没有背过模板,考场上找规律应该更容易过一点) |
1140 Look-and-say Sequence (20 分)
思路:
- 找规律:出现的数字+该数字连续出现的次数……依次类推
- 字符串处理:string与int之间的相互转化
#include
using namespace std;
int d,n;
//1 2 3 4 5 6 7 8
//D D1 D111 D113 D11231
bool vis[10];
int Count(string str, char ch){
int ans=0;
for(int i=0;i<str.length();i++){
if(str[i]==ch){
ans++;
}
}
return ans;
}
string getAns(){
//计算出d的第n个
string nth=to_string(d);
string n1th="";
for(int i=1;i<n;i++){
//初始化
//for(int k=0;k<10;k++)vis[k]=false;
n1th="";
for(int j=0;j<nth.size();j++){
int temp=1;
n1th+=nth[j];
while(j+1<nth.size()&&nth[j]==nth[j+1]){
j++;
temp++;
}
n1th+=to_string(temp);
}
nth=n1th;
//cout<< nth<
}
return nth;
}
int main(){
scanf("%d%d",&d,&n);
cout<<getAns();
return 0;
}
1141 PAT Ranking of Institutions (25 分)
思路:
基本的字符串处理+排序,没有坑
学习到的一个新的string用法:
因为tolower()只支持一个字符一个字符修改,下面可以快速转化一个string(其实自己写转化函数也不费劲)
transform(iid.begin(),iid.end(),iid.begin(),::tolower);
#include
using namespace std;
struct Institution{
string name;
int TWS=0;
int Ns=0;
int scoreA=0;
int scoreB=0;
int scoreT=0;
};
map<string,Institution>mp;
int n;
string id;
int score;
string iid;
vector<Institution>v;
bool cmp(Institution a,Institution b){
if(a.TWS!=b.TWS){
return a.TWS>b.TWS;
}else if(a.Ns!=b.Ns){
return a.Ns<b.Ns;
}else{
return a.name<b.name;
}
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++){
cin>>id>>score>>iid;
//注意写法
transform(iid.begin(),iid.end(),iid.begin(),::tolower);
if(id[0]=='A'){
mp[iid].scoreA+=score;
}else if(id[0]=='B'){
mp[iid].scoreB+=score;
}else if(id[0]=='T'){
mp[iid].scoreT+=score;
}
mp[iid].Ns++;
mp[iid].name=iid;
}
printf("%d\n",mp.size());
for(map<string,Institution>::iterator it=mp.begin();it!=mp.end();it++){
Institution temp=it->second;
//temp
temp.TWS=temp.scoreA+temp.scoreB/1.5+temp.scoreT*1.5;
v.push_back(temp);
}
sort(v.begin(),v.end(),cmp);
int rank=1;
for(int i=0;i<v.size();i++){
if(i&&v[i].TWS!=v[i-1].TWS){
rank=i+1;
}
cout<<rank<<" "<<v[i].name<<" "<<v[i].TWS<<" "<<v[i].Ns<<endl;
}
return 0;
}
1142 Maximal Clique (25 分)
思路:
基础图论
- 首先判断给定点集是否两两相连(并在此时给点集中的点标记)
- 其次判断是否有一个点不属于点集但是和点集中的所有点相连
- 因为没怎么卡时间,所以暴力也基本可以
#include
using namespace std;
int n,m,k;
int num;
const int maxn=206;
int a,b;
bool graph[maxn][maxn]={false};
int v[maxn];
int vis[maxn]={0};
bool isADJ(int num){
for(int i=0;i<num;i++){
vis[i]=k;
for(int j=i+1;j<num;j++){
if(!graph[v[i]][v[j]]){
return false;
}
}
}
return true;
}
bool canADD(int num,int sign){
bool flag=false;
for(int id=1;id<=n;id++){
if(vis[id]!=sign){
for(int i=0;i<num;i++){
if(graph[v[i]][id]==false){
break;
}
if(i==num-1&&graph[v[i]][id]==true){
return true;
}
}
}
}
return false;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
scanf("%d%d",&a,&b);
graph[a][b]=true;
graph[b][a]=true;
}
scanf("%d",&k);
for(int i=0;i<k;i++){
scanf("%d",&num);
for(int j=0;j<num;j++){
scanf("%d",&v[j]);
}
//任意两个顶点都是有邻接的边的
if(!isADJ(num)){
printf("Not a Clique\n");
}else if(canADD(num,k)){
printf("Not Maximal\n");
}else{
printf("Yes\n");
}
//没有办法再加任何一个邻接边
}
return 0;
}
[1143 Lowest Common Ancestor (30 分)](题目详情 - 1143 Lowest Common Ancestor (30 分) (pintia.cn))
狠狠订正嗷嗷嗷嗷
一开始的思路:
- 建立一棵树(模板,建议熟悉)
- 对于给定两个结点,首先Find看是否存在,并在寻找的过程中保存父节点(即经过的结点)
- 比较沿路经过的父节点,是否有出现在同一层同一大小的结点,若有,即为公共父节点(具体情况还需要特判,若两个结点相等并且等于父节点,属于:
X is an ancestor of Y
情况)
第一版:18/30
#include
using namespace std;
//最低的祖先
int m,n;
int v;
struct Node{
int val;
Node *right=NULL;
Node *left=NULL;
};
Node *build(int val,Node*root){
if(root==NULL){
root=new Node;
root->val=val;
}else if(val<root->val){
root->left=build(val,root->left);
}else{
root->right=build(val,root->right);
}
return root;
}
//找到最年轻的父节点
int a,b;
vector<int>v1;
vector<int>v2;
bool Find(int val,Node*root,int sign){
if(root==NULL){
return false;
}else if(root->val==val){
if(sign==1){
v1.push_back(root->val);
}else{
v2.push_back(root->val);
}
return true;
}else{
//保存路径上的值
if(sign==1){
v1.push_back(root->val);
}else{
v2.push_back(root->val);
}
if(val<root->val){
return Find(val,root->left,sign);
}else{
return Find(val,root->right,sign);
}
}
}
map<int,bool>mp;
int main(){
scanf("%d%d",&m,&n);
Node *root=NULL;
for(int i=0;i<n;i++){
scanf("%d",&v);
mp[v]=true;
root=build(v,root);
}
for(int i=0;i<m;i++){
v1.clear();
v2.clear();
scanf("%d%d",&a,&b);
if(!mp[a]||!Find(a,root,1)){
if(!mp[b]||!Find(b,root,2)){
printf("ERROR: %d and %d are not found.\n",a,b);
}else{
printf("ERROR: %d is not found.\n",a);
}
}else if(!mp[b]||!Find(b,root,2)){
printf("ERROR: %d is not found.\n",b);
}else{
//找到路径上公共点
int ans=-1;
for(int i=0;i<min(v1.size(),v2.size());i++){
if(v1[i]==v2[i]){
ans=v1[i];
}
}
if(ans==a&&ans!=b){
printf("%d is an ancestor of %d.\n",ans,b);
}else if(ans==b&&ans!=a){
printf("%d is an ancestor of %d.\n",ans,a);
}else if(ans==a&&ans==b){
printf("%d is an ancestor of %d.\n",ans,a);
}else{
printf("LCA of %d and %d is %d.\n",a,b,ans);
}
}
}
return 0;
}
第二版:试着将Find优化在build部分就储存父节点,还是不行18/30
#include
using namespace std;
//最低的祖先
int m,n;
int v;
struct Node{
int val;
Node *right=NULL;
Node *left=NULL;
};
map<int,bool>mp;
map<int,vector<int> >path;
Node *build(int val,Node*root){
if(root==NULL){
root=new Node;
root->val=val;
path[val].push_back(val);
}else if(val<root->val){
path[val].push_back(root->val);
root->left=build(val,root->left);
}else{
path[val].push_back(root->val);
root->right=build(val,root->right);
}
return root;
}
//找到最年轻的父节点
int a,b;
int main(){
scanf("%d%d",&m,&n);
Node *root=NULL;
for(int i=0;i<n;i++){
scanf("%d",&v);
mp[v]=true;
root=build(v,root);
}
for(int i=0;i<m;i++){
scanf("%d%d",&a,&b);
if(!mp[a]){
if(!mp[b]){
printf("ERROR: %d and %d are not found.\n",a,b);
}else{
printf("ERROR: %d is not found.\n",a);
}
}else if(!mp[b]){
printf("ERROR: %d is not found.\n",b);
}else{
//找到路径上公共点
int ans=-1;
for(int i=min(path[a].size(),path[b].size())-1;i>=0;i--){
if(path[a][i]==path[b][i]){
ans=path[a][i];
break;
}
}
if(ans==a&&ans!=b){
printf("%d is an ancestor of %d.\n",ans,b);
}else if(ans==b&&ans!=a){
printf("%d is an ancestor of %d.\n",ans,a);
}else if(ans==a&&ans==b){
printf("%d is an ancestor of %d.\n",ans,a);
}else{
printf("LCA of %d and %d is %d.\n",a,b,ans);
}
}
}
return 0;
}
看了柳神的思路才知道不需要建立树,考察的是对于BST树数组结构
订正思路:
分析:map
mp用来标记树中所有出现过的结点,遍历一遍pre数组,将当前结点标记为a,如果u和v分别在a的左、右,或者u、v其中一个就是当前a,说明找到了这个共同最低祖先a,退出当前循环~最后根据要求输出结果即可~
#include
using namespace std;
int m,n;
vector<int>pre;
map<int,bool>mp;
int u,v;
int main(){
scanf("%d%d",&m,&n);
pre.resize(n);
for(int i=0;i<n;i++){
scanf("%d",&pre[i]);
mp[pre[i]]=true;
}
for(int i=0;i<m;i++){
scanf("%d%d",&v,&u);
if(!mp[v]){
if(!mp[u]){
printf("ERROR: %d and %d are not found.\n",v,u);
}else{
printf("ERROR: %d is not found.\n",v);
}
}else {
if(!mp[u]){
printf("ERROR: %d is not found.\n",u);
}else{
//找到了
int ans=-2;
int temp;
for(int j=0;j<n;j++){
temp=pre[j];
if(temp<u&&temp>v||temp<v&&temp>u||temp==u||temp==v){
ans=temp;
break;
}
}
if(temp!=v&&temp!=u){
printf("LCA of %d and %d is %d.\n",v,u,ans);
}else{
printf("%d is an ancestor of %d.\n",ans,ans==v?u:v);
}
}
}
}
}