Group Programming Ladder Competition-L2 Group

Group Programming Ladder Competition-L2 Group

--------------------------------------------------------------------------------

Question portal

Group Programming Ladder Competition-L2 Group
--------------------------------------------- ----------------------------------
For more details, see >>

OJ problem solution series directory navigation post
------------------------------------------------- ----------------------------------

sequence

This is the Group Programming Ladder Competition - Group L2
Group Programming Ladder Competition, referred to as the CCCC competition. Generally speaking, this competition is not difficult. You can get good scores by mastering the basic data structures and algorithms. L1/L2/L3 Arranged in order of increasing difficulty, L1 is the entry-level difficulty, similar to the first three questions of the PAT Level B exam, accounting for 100 points; L2 level adds elements of data structure, and the difficulty is the same as the last two questions of PAT Level B/PAT Level A The first three questions are of equal difficulty, accounting for 75 points. Level L3 adds advanced algorithm content, and the difficulty is the same as the last question of PAT Level A/PAT Top Level, accounting for 75 points. Therefore, you can also refer to the PAT topic section when practicing. For details, see the OJ problem solution series directory navigation post.

Next is the problem solution part. Each algorithm question is marked with the corresponding algorithm label. For those who are error-prone, difficult or Questions with special test points will be highlighted. The recommended questions in this chapter are:

L2-012 Judgment about heaps (25 points) Heap + string
L2-013 Red Alert (25 minutes) And search the collection
L2-014 Train dispatching (25 minutes) monotonic queue
L2-016 May all lovers in the world be long-lost brothers and sisters (25 points)
L2-030 Icelanders (25 points)
Union search + DFS/BFS
L2-018 Divide polynomial A by B (25 points) high precision
L2-028 Show affection and get points quickly (25 points) string + enum
L2-034 Mask distribution (25 minutes) Big simulation + sorting
L2-035 Level-order traversal of a complete binary tree (25 points) Tree, binary tree + traversal

--------------------------------------------------------------------------------

L2-001 Emergency Rescue (25 minutes)

Algorithm tag: graph theory + dijkstra + dfs
Note: dijkstra runs the shortest path, counts the number of paths at the same time, and updates the maximum point weight. It is a standard template question. For details, see the data structure topic series-graph theory

#include<bits/stdc++.h>
using namespace std;
int N,M,S,D;
const int maxn = 505;
int dp[maxn];
int num[maxn];
int pre[maxn];
int weight[maxn];
bool vis[maxn];
int a[maxn];
struct node{
    
    
	int v;
	int w;
};
node temp;
vector<node> G[maxn];
void Dijkstra(int S){
    
    
	memset(vis,0,sizeof(vis));
	memset(dp,0x3f,sizeof(dp));
	memset(num,0,sizeof(num));
	memset(weight,0,sizeof(weight));
	dp[S] = 0;
	num[S] = 1;
	weight[S] = a[S];
	priority_queue<pair<int,int> > q;
	q.push(make_pair(-dp[S],S));
	while(!q.empty()){
    
    
		pair<int,int> f = q.top();
		q.pop();
		int u = f.second;
		if(vis[u]){
    
    
			continue;
		}
		vis[u] = true;
		for(int i=0;i<G[u].size();i++){
    
    
			int v = G[u][i].v;
			int w = G[u][i].w;
			if(!vis[v]){
    
    
				if(dp[u]+w<dp[v]){
    
    
					dp[v] = dp[u] + w;
					num[v] = num[u];
					weight[v] = weight[u] + a[v];
					pre[v] = u;
					q.push(make_pair(-dp[v],v));
				}else if(dp[u]+w==dp[v]){
    
    
					num[v] += num[u];
					if(weight[u]+a[v]>weight[v]){
    
    
						weight[v] = weight[u] + a[v];
						pre[v] = u;
					}
				}
			}
		}
	}
}
vector<int> ans;
void Dfs(int u){
    
    
	if(u == S){
    
    
		ans.push_back(u);
		return;
	}
	Dfs(pre[u]);
	ans.push_back(u);
}
int main(){
    
    
	cin >> N >> M >> S >> D;	
	for(int i=0;i<N;i++){
    
    
		cin >> a[i];
	} 
	for(int i=1;i<=M;i++){
    
    
		int u,v,w;
		cin >> u >> v >> w;
		temp.v = v;
		temp.w = w;
		G[u].push_back(temp);
		temp.v = u;
		G[v].push_back(temp);
	}
	Dijkstra(S);
	cout << num[D] << " " << weight[D] << endl;
	Dfs(D);
	for(int i=0;i<ans.size();i++){
    
    
		if(i==0){
    
    
			printf("%d",ans[i]);
		}else{
    
    
			printf(" %d",ans[i]);
		} 
	}
	return 0;
} 

L2-002 Linked list deduplication (25 points)

Algorithm tag: simulation + linked list

#include<bits/stdc++.h>
using namespace std;
struct node{
    
    
	int value;
	int next;
};
const int maxn = 1e5+5;
node n[maxn];

int ori_add[maxn];
int ori_value[maxn];
int post_add[maxn];
int post_value[maxn];
int cnt1 = 0;
int cnt2 = 0;
set<int> s;

int main(){
    
    
	int start;
	int N;
	cin >> start >> N;
	for(int i=0;i<N;i++){
    
    
		int y;
		scanf("%d",&y);
		scanf("%d%d",&n[y].value,&n[y].next);
	}
	while(start!=-1){
    
    
		if(s.find(abs(n[start].value))!=s.end()){
    
    
			post_add[cnt2] = start;
			post_value[cnt2] = n[start].value;
			cnt2++; 
		}else{
    
    
			ori_add[cnt1] = start;
			ori_value[cnt1] = n[start].value;
			s.insert(abs(n[start].value));
			cnt1++;
		}
		start = n[start].next;
	} 
	for(int i=0;i<cnt1;i++){
    
    
		if(i!=cnt1-1){
    
    
			printf("%05d %d %05d\n",ori_add[i],ori_value[i],ori_add[i+1]);
		}else{
    
    
			printf("%05d %d -1\n",ori_add[i],ori_value[i]);
		}
	}
	for(int i=0;i<cnt2;i++){
    
    
		if(i!=cnt2-1){
    
    
			printf("%05d %d %05d\n",post_add[i],post_value[i],post_add[i+1]);
		}else{
    
    
			printf("%05d %d -1\n",post_add[i],post_value[i],post_add[i+1]);
		}
	}
	return 0;
} 

L2-003 Mooncake(25 points)

Algorithm tag: Simple version of complete backpack

#include<bits/stdc++.h>
using namespace std;
int N,D;
int maxn = 1005;
typedef struct mooncake{
    
    
	double num;
	double price;
	double singleprice;
}mooncake;
bool cmp(mooncake m1,mooncake m2){
    
    
	return m1.singleprice > m2.singleprice;
}
int main(){
    
    
	cin >> N >> D;
	mooncake m[N];
	for(int i=0;i<N;i++){
    
    
		cin >> m[i].num;
	}
	for(int i=0;i<N;i++){
    
    
		cin >> m[i].price;
	}
	for(int i=0;i<N;i++){
    
    
		m[i].singleprice = (m[i].price * 1.0) /(m[i].num * 1.0);
	}
	
	sort(m,m+N,cmp);
	
	int site = 0;
	double totalprice = 0.0;
	
	while(D!=0){
    
    
		if(m[site].num <= D){
    
    
			D -= m[site].num;
			totalprice = totalprice + m[site].price;
		}else{
    
    
			totalprice = totalprice + m[site].singleprice * D;
			D = 0;
		}
		site++;
	}
	printf("%.2lf\n",totalprice);
	
	return 0;
}

L2-004 Is this a binary search tree? (25 points)

Algorithm tags: tree, binary tree + traversal
Note: The so-called mirror tree actually refers to reversing the access order of the left and right subtrees. All other conditions remain unchanged. Therefore, this question is still essentially an examination of tree construction + traversal.

#include<bits/stdc++.h>
using namespace std;

vector<int> pre,preM,post,postM,origin;

int N; 
struct node{
    
    
	int data;
	node* lchild;
	node* rchild;
};

node* root = NULL;

void insert(node* &root,int x){
    
    
	if(root==NULL){
    
    
		node *Node = new node;
		Node->data = x;
		Node->lchild = NULL;
		Node->rchild = NULL;
		root = Node;
		return;
	}
	if(x<root->data){
    
    
		insert(root->lchild,x);
	}else{
    
    
		insert(root->rchild,x);
	}
}

int cnt = 0;

void PreOrder(node* root,vector<int> &pre){
    
    
	if(root==NULL){
    
    
		return;
	}
	pre.push_back(root->data);
	PreOrder(root->lchild,pre);
	PreOrder(root->rchild,pre);
}

void MirrorOrder(node *root,vector<int> &preM){
    
    
	if(root==NULL){
    
    
		return;
	}
	preM.push_back(root->data);
	MirrorOrder(root->rchild,preM);
	MirrorOrder(root->lchild,preM);
}

void PostOrder(node* root,vector<int> &post){
    
    
	if(root==NULL){
    
    
		return;
	}
	PostOrder(root->lchild,post);
	PostOrder(root->rchild,post);
	post.push_back(root->data);
}

void PostOrder1(node* root,vector<int> &postM){
    
    
	if(root==NULL){
    
    
		return;
	}
	PostOrder1(root->rchild,postM);
	PostOrder1(root->lchild,postM);
	postM.push_back(root->data);
}

int main(){
    
    
	cin >> N;
	for(int i=0;i<N;i++){
    
    
		int t;
		cin >> t;
		origin.push_back(t);
		insert(root,t);
	}
	
	PreOrder(root,pre);
	MirrorOrder(root,preM);
	
	if(pre==origin){
    
    
		printf("YES\n");
		PostOrder(root,post);
		for(int i=0;i<post.size();i++){
    
    
			if(i==0){
    
    
				printf("%d",post[i]);
			}else{
    
    
				printf(" %d",post[i]);
			}
		}
	}else if(preM==origin){
    
    
		printf("YES\n");
		PostOrder1(root,postM);
		for(int i=0;i<postM.size();i++){
    
    
			if(i==0){
    
    
				printf("%d",postM[i]);
			}else{
    
    
				printf(" %d",postM[i]);
			}
		}
	}else{
    
    
		printf("NO\n");
	}
	
	return 0;
}

L2-005 Set similarity (25 points)

Algorithm tag: Set
Note: The focus of this question is sets. Since the elements in the set cannot be repeated, STL's set can be used to operate. Each query inputs the numbers of two sets. We use the enumeration method to determine the similarity of the sets. , and finally output after retaining 2 decimal places.

#include<bits/stdc++.h>
using namespace std;
set<int> a[55];
double query[60][60];
int main(){
    
    
    int N;
    scanf("%d",&N);
    for(int i=1;i<=N;i++){
    
    
        int M;
        scanf("%d",&M);
        for(int j=0;j<M;j++){
    
    
            int t;
            scanf("%d",&t);
            a[i].insert(t);
        }
    }
     
    int K;
    scanf("%d",&K);
    for(int i=0;i<K;i++){
    
    
        int g,h;
        scanf("%d%d",&g,&h);
        set<int>::iterator it1;
        set<int>::iterator it2;
        int Nc = 0;
        for(it1 = a[g].begin(),it2 = a[h].begin();it1!=a[g].end() && it2!=a[h].end();){
    
    
            if(*it1 == *it2){
    
    
                Nc++;
                it1++;
                it2++;
            }else if(*it1<*it2){
    
    
                it1++;
            }else{
    
    
                it2++;
            }
        }
        int Nn = a[g].size() + a[h].size() - Nc;
        double r = (Nc * 1.0) /(Nn * 1.0);
        printf("%.2lf%%\n",r*100.0);
    }
    return 0;
} 

L2-006 Tree traversal (25 points)

Algorithm tags: tree, binary tree + traversal
Note: First enter in-order traversal and post-order traversal to build a tree, and then start from the root node and perform hierarchical traversal

#include<bits/stdc++.h>
using namespace std;

int post[35];
int in[35];
struct node{
    
    
	int data;
	node* lchild;
	node* rchild;
};
node* root = NULL;
node* newnode(int v){
    
    
	node* Node = new node;
	Node->data = v;
	Node->lchild = NULL;
	Node->rchild = NULL; 
	return Node;	
} 
node* Create(int inL,int inR,int postL,int postR){
    
    
	if(postL>postR){
    
    
		return NULL;
	}
	int d = post[postR];
	int k;
	for(int i=inL;i<=inR;i++){
    
    
		if(in[i]==d){
    
    
			k = i;
			break;
		}
	}
	int numleft = k-inL;
	node* Node = new node;
	Node->data = d; 
	Node->lchild = Create(inL,k-1,postL,postL+numleft-1);
	Node->rchild = Create(k+1,inR,postL+numleft,postR-1); 
	return Node;
}
queue<node*> q;
int n;
void Level(node* root){
    
    
	int T = n;
	q.push(root);
	while(!q.empty()){
    
    
		node* f = q.front();
		q.pop();
		if(T==1){
    
    
			printf("%d\n",f->data);
		}else{
    
    
			printf("%d ",f->data);
		}
		T--;
		if(f->lchild){
    
    
			q.push(f->lchild);
		}
		if(f->rchild){
    
    
			q.push(f->rchild);
		}
	}
}
int main(){
    
    
	cin >> n;
	for(int i=0;i<n;i++){
    
    
		cin >> post[i];
	}	
	for(int i=0;i<n;i++){
    
    
		cin >> in[i];
	}
	root = Create(0,n-1,0,n-1);
	Level(root);
	return 0;
}

L2-007 Family Property (25 points)

Algorithm tag: Union-find + sorting
Note: This question is easily confused with tree and binary tree knowledge points. The correct solution to this question is the union-find operation, merging parent and child, and then delimiting the area.

#include<bits/stdc++.h>
using namespace std;
struct person{
    
    
	int father;
	int mother;
	vector<int> child;
	int Mstate;
	int Area;
	bool f = false;
};
person p[10005];

int father[10005];

int findfather(int x){
    
    
	if(x == father[x]){
    
    
		return x;
	}else{
    
    
		int F = findfather(father[x]);
		father[x] = F;
		return F;	
	}
}

void Union(int a,int b){
    
    
	int fa = findfather(a);
	int fb = findfather(b);
	if(fa!=fb){
    
    
		if(fa<fb){
    
    
			father[fb] = fa;
		}else{
    
    
			father[fa] = fb;	
		}
	}
}

int num[10005];
double area[10005];
double state[10005];


struct ans{
    
    
	int ID;
	int number;
	double state;
	double area;
};
ans a[10005];

bool vis[10005];
bool hashT[10005];

int cnt = 0;

bool cmp(ans a1,ans a2){
    
    
	if(a1.area!=a2.area){
    
    
		return a1.area > a2.area;
	}else{
    
    
		return a1.ID < a2.ID;	
	}
}

int main(){
    
    
	for(int i=0;i<=9999;i++){
    
    
		father[i] = i;
	}
	int N;
	scanf("%d",&N);
	for(int i=0;i<N;i++){
    
    
		int id;
		scanf("%d",&id);
		hashT[id] = true;
		scanf("%d%d",&p[id].father,&p[id].mother);
		if(p[id].father!=-1){
    
    
			hashT[p[id].father] = true;
			Union(id,p[id].father);
		}
		if(p[id].mother!=-1){
    
    
			hashT[p[id].mother] = true;
			Union(id,p[id].mother);
		}
		int k;
		scanf("%d",&k);
		for(int j=0;j<k;j++){
    
    
			int cid;
			scanf("%d",&cid);
			p[id].child.push_back(cid);
			hashT[cid] = true;
			Union(id,cid);
		}
		scanf("%d%d",&p[id].Mstate,&p[id].Area);
		p[id].f = true;
	}
	
	
	for(int i=0;i<=9999;i++){
    
    
		int F = findfather(i);
		num[F]++;
		if(p[i].f){
    
    
			area[F] += p[i].Area;
			state[F] += p[i].Mstate;
		}
	}
	
	for(int i=0;i<=9999;i++){
    
    
		if(hashT[i]){
    
    
			int F = findfather(i);
			if(!vis[F] && num[F]){
    
    
				vis[F] = true;
				a[cnt].ID = i;
				a[cnt].number = num[F];
				a[cnt].state = state[F]/(num[F]*1.0);
				a[cnt].area = area[F]/(num[F]*1.0);
				cnt++;
			}	
		}
	}
	
	sort(a,a+cnt,cmp);
	printf("%d\n",cnt);
	for(int i=0;i<cnt;i++){
    
    
		printf("%04d %d %.3lf %.3lf\n",a[i].ID,a[i].number,a[i].state,a[i].area);
	}
	
	return 0;
} 

L2-008 Longest symmetric substring (25 points)

Algorithm tag: DP
Note: Dynamic programming to find the longest palindrome substring, the initial conditions can be obtained as follows:
Let dp [ i ] [ j ] dp [i] [j]d p ​​[ i ] [ j ] means that the i-th character to the j-th character is a palindrome string, then
dp [ i ] [ i ] = 1 , L = 1 dp[i][i]=1,L= 1dp[i][i]=1,L=1
d p [ i ] [ i + 1 ] = 1 , s [ i ] = = s [ i + 1 ] , L = 2 dp[i][i+1]=1,s[i]==s[i+1],L=2 dp[i][i+1]=1,s[i]==s[i+1],L=2
d p [ i ] [ j ] = 1 , d p [ i + 1 ] [ j − 1 ] = 1 且 s [ i ] = = s [ j ] , L > = 3 dp[i][j]=1,dp[i+1][j-1]=1且s[i]==s[j],L>=3 dp[i][j]=1,dp[i+1][j1]=1s[i]==s[j],L>=3

#include<bits/stdc++.h>
using namespace std;
int dp[1005][1005];

int main(){
    
    
	string s;
	getline(cin,s);
	int len = s.size();
	int ans = 1;
	for(int i=0;i<len;i++){
    
    
		dp[i][i] = 1;
		if(i>=1 && s[i-1]==s[i]){
    
    
			dp[i-1][i] = 1;
			ans = 2;
		}
	}
	
	for(int i=3;i<=len;i++){
    
    
		for(int j=0;j<len-i+1;j++){
    
    
			int k = j+i-1;
			if(s[k] == s[j] && dp[j+1][k-1]==1){
    
    
				dp[j][k] = 1;
				ans = i;
			}
		}
	}
	cout << ans << endl;
	return 0; 
}

L2-009 抢红包 (25 分)

算法标签: 排序

#include<bits/stdc++.h>
using namespace std;
struct node{
    
    
	double price = 0.0;
	int num = 0;
	int number;	
};
const int maxn = 1e4+5;
node stu[maxn];
bool cmp(node stu1,node stu2){
    
    
	if(fabs(stu1.price-stu2.price)>1e-3){
    
    
		return stu1.price>stu2.price;
	}else if(stu1.num!=stu2.num){
    
    
		return stu1.num>stu2.num;
	}else{
    
    
		return stu1.number<stu2.number;
	}
}
int main(){
    
    
	int N;
	scanf("%d",&N);
	for(int i=1;i<=N;i++){
    
    
		stu[i].number = i;
		int K;
		scanf("%d",&K);
		for(int j=1;j<=K;j++){
    
    
			int id,v;
			scanf("%d%d",&id,&v);
			stu[i].price -= (v/100.0);
			stu[id].price += (v/100.0);
			stu[id].num++;
		}
	}
	sort(stu+1,stu+N+1,cmp);
	for(int i=1;i<=N;i++){
    
    
		printf("%d %.2lf\n",stu[i].number,stu[i].price);
	}
	return 0;
}

L2-010 排座位 (25 分)

算法标签: 并查集

#include<bits/stdc++.h>
using namespace std;
int N,M,K;
int father[105];
int findfather(int x){
    
    
	if(x==father[x]){
    
    
		return x;
	}else{
    
    
		int F = findfather(father[x]);
		father[x] = F;
		return F;	
	}
}
void Union(int a,int b){
    
    
	int fA = findfather(a);
	int fB = findfather(b);
	if(fA!=fB){
    
    
		father[fA] = fB;
	}
}

set<int> s2[105];
int main(){
    
    
	scanf("%d%d%d",&N,&M,&K);
	for(int i=1;i<=N;i++){
    
    
		father[i] = i;
	}
	for(int i=1;i<=M;i++){
    
    
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		if(w==1){
    
    
			Union(u,v);
		}else{
    
    
			s2[u].insert(v);
			s2[v].insert(u);
		}
	}
	for(int i=1;i<=K;i++){
    
    
		int u,v;
		scanf("%d%d",&u,&v);
		int fu = findfather(u);
		int fv = findfather(v);
		if(fu==fv && s2[u].find(v)==s2[u].end()){
    
    
			printf("No problem\n");
		}else if(fu!=fv && s2[u].find(v)==s2[u].end()){
    
    
			printf("OK\n");
		}else{
    
    
			if(fu!=fv && s2[u].find(v)!=s2[u].end()){
    
    
				printf("No way\n");
			}else{
    
    
				printf("OK but...\n");
			}
		}
	}
	
	return 0;
}

L2-011 玩转二叉树 (25 分)

算法标签: 树,二叉树 + 遍历
注意点: 根据中序遍历和先序遍历建树,然后层序遍历即可

#include<bits/stdc++.h>
using namespace std;
int in[35];
int pre[35];

struct node{
    
    
	int data;
	node* lchild;
	node* rchild;
};

node* newnode(int v){
    
    
	node* Node = new node;
	Node->data = v;
	Node->lchild = NULL;
	Node->rchild = NULL;
	return Node;
}

node* Create(int preL,int preR,int inL,int inR){
    
    
	if(preL>preR){
    
    
		return NULL;
	}
	node* root = newnode(pre[preL]);
	int k;
	for(int i=inL;i<=inR;i++){
    
    
		if(pre[preL] == in[i]){
    
    
			k = i;
			break;
		}
	}
	int numleft = k-inL;
	root->lchild = Create(preL+1,preL+numleft,inL,inL+numleft-1);
	root->rchild = Create(preL+numleft+1,preR,inL+numleft+1,inR);
	return root;
}
void levelorder(node* root){
    
    
	queue<node*> q;
	q.push(root);
	bool f1 = true;
	while(!q.empty()){
    
    
		node* f = q.front();
		q.pop();
		if(f1){
    
    
			cout << f->data;
			f1 = false;
		}else{
    
    
			cout << " " << f->data;
		}
		if(f->rchild){
    
    
			q.push(f->rchild);
		}
		if(f->lchild){
    
    
			q.push(f->lchild);
		}
	} 
}
int main(){
    
    
	int n;
	cin >> n;
	for(int i=0;i<n;i++){
    
    
		cin >> in[i];
	}
	for(int i=0;i<n;i++){
    
    
		cin >> pre[i];
	}
	node* root = NULL;
	root = Create(0,n-1,0,n-1);
	levelorder(root);
	
	return 0;
} 

L2-012 关于堆的判断 (25 分)

算法标签: 堆 + 字符串
注意点: 本题考察堆的插入操作:
1.本题容易与Floyd建堆混淆,题目中明确要求逐个元素插入到堆中,因此,是采用自下而上的上滤算法建堆,而不是采用自下而上的下滤算法建堆
2.如何判断这四类操作
(1)根结点很显然,判断a[1]是否与输入的root相等
(2)判断兄弟结点,拥有共同的父节点,判断n1/2 == n2/2
(3)判断父节点,n2/2 == n1
(4)判断子节点,n1/2 == n2
3.字符串中数字的读入,这里有一个坑点,负数如-1003,需特判前面的负号[测试点1]/[测试点3]

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e4+5;
int a[maxn];
void downadjust(int N){
    
    
	while(N>=2){
    
    
		if(a[N]<a[N/2]){
    
    
			swap(a[N],a[N/2]);
		}else{
    
    
			break;
		}
		N/=2;
	}
}
int main(){
    
    
	int N,M;
	cin >> N >> M;
	for(int i=1;i<=N;i++){
    
    
		cin >> a[i];
		downadjust(i);
	}
	getchar();
	for(int i=1;i<=M;i++){
    
    
		string s;
		getline(cin,s);
		if(s.find("is the root")!=-1){
    
    
			int site = s.find(" is the root");
			int num = 0;
			if(s[0] == '-'){
    
    
				for(int i=1;i<site;i++){
    
    
					num = num*10 + s[i] - '0';
				}
				num = -num;
			}else{
    
    
				for(int i=0;i<site;i++){
    
    
					num = num*10 + s[i] - '0';
				}	
			}
			if(a[1] == num){
    
    
				printf("T\n");
			}else{
    
    
				printf("F\n");
			}
		}else if(s.find("are siblings")!=-1){
    
    
			int site1 = s.find(" and");
			int num1 = 0;
			if(s[0] == '-'){
    
    
				for(int i=1;i<site1;i++){
    
    
					num1 = num1*10 + s[i] - '0';
				}
				num1 = -num1;
			}else{
    
    
				for(int i=0;i<site1;i++){
    
    
					num1 = num1*10 + s[i] - '0';
				}	
			}
			int site2 = s.find("and ");
			int site3 = s.find(" are");
			int num2 = 0;
			if(s[site2+4] == '-'){
    
    
				for(int i=site2+5;i<site3;i++){
    
    
					num2 = num2*10 + s[i] - '0';
				}
				num2 = -num2;
			}else{
    
    
				for(int i=site2+4;i<site3;i++){
    
    
					num2 = num2*10 + s[i] - '0';
				}	
			}
			int ans1,ans2;
			for(int i=1;i<=N;i++){
    
    
				if(num1 == a[i]){
    
    
					ans1 = i;
					break;
				}
			}
			for(int i=1;i<=N;i++){
    
    
				if(num2 == a[i]){
    
    
					ans2 = i;
					break;
				}
			}
			if(ans1/2 == ans2/2){
    
    
				printf("T\n");
			}else{
    
    
				printf("F\n");
			}
		}else if(s.find("is the parent of")!=-1){
    
    
			int site1 = s.find(" is");
			int num1 = 0;
			if(s[0] == '-'){
    
    
				for(int i=1;i<site1;i++){
    
    
					num1 = num1*10 + s[i] - '0';
				}
				num1 = -num1;
			}else{
    
    
				for(int i=0;i<site1;i++){
    
    
					num1 = num1*10 + s[i] - '0';
				}	
			}
			int site2 = s.find("of ");
			int num2 = 0;
			if(s[site2+3] == '-'){
    
    
				for(int i=site2+4;i<s.size();i++){
    
    
					num2 = num2*10 + s[i] - '0';
				}
				num2 = -num2;
			}else{
    
    
				for(int i=site2+3;i<s.size();i++){
    
    
					num2 = num2*10 + s[i] - '0';
				}	
			}
			int ans1,ans2;
			for(int i=1;i<=N;i++){
    
    
				if(num1 == a[i]){
    
    
					ans1 = i;
					break;
				}
			}
			for(int i=1;i<=N;i++){
    
    
				if(num2 == a[i]){
    
    
					ans2 = i;
					break;
				}
			}
			if(ans2/2==ans1){
    
    
				printf("T\n");
			}else{
    
    
				printf("F\n");
			}
		}else{
    
    
			int site1 = s.find(" is");
			int num1 = 0;
			if(s[0] == '-'){
    
    
				for(int i=1;i<site1;i++){
    
    
					num1 = num1*10 + s[i] - '0';
				}
				num1 = -num1;
			}else{
    
    
				for(int i=0;i<site1;i++){
    
    
					num1 = num1*10 + s[i] - '0';
				}
			}
			int site2 = s.find("of ");
			int num2 = 0;
			if(s[site2+3] == '-'){
    
    
				for(int i=site2+4;i<s.size();i++){
    
    
					num2 = num2*10 + s[i] - '0';
				}
				num2 = -num2;
			}else{
    
    
				for(int i=site2+3;i<s.size();i++){
    
    
					num2 = num2*10 + s[i] - '0';
				}	
			}
			int ans1,ans2;
			for(int i=1;i<=N;i++){
    
    
				if(num1 == a[i]){
    
    
					ans1 = i;
					break;
				}
			}
			for(int i=1;i<=N;i++){
    
    
				if(num2 == a[i]){
    
    
					ans2 = i;
					break;
				}
			}
			if(ans1/2==ans2){
    
    
				printf("T\n"); 
			}else{
    
    
				printf("F\n");
			}
		}
	}
	
	return 0;
} 

L2-013 红色警报 (25 分)

算法标签: 并查集
注意点: 本题考察的算法是并查集,但考察的是并查集的一种变式:如何理解题目所给的条件(失去一个城市并不改变其他城市之间的连通性)
首先我们来分析一下这个条件:
(1)若失去一个城市之后。连通图数量减少了1:那么失去的城市本身就是一个连通分量,它并不影响其他城市的连通性
(2)若失去一个城市之后,连通图数量不变:此时意味着本来是若干个连通分量,删除结点后,仍然是若干个连通分量,这些连通分量中的城市互相可达,说明删除这个城市并不影响其他城市的连通性
(3)若失去一个城市之后,连通图数量增加了1:此时意味着多出来的连通分量必定是原连通分量裂开后形成的,此时破坏了其余城市之间的连通性,因此这种情况下会发出alert

#include<bits/stdc++.h>
using namespace std;
const int maxn = 505;
bool hashT[maxn];
vector<int> G[maxn];
int a[maxn];
int father[maxn];
vector<int> res;
int findfather(int x){
    
    
	if(x==father[x]){
    
    
		return x;
	}else{
    
    
		int F = findfather(father[x]);
		father[x] = F;
		return F;	
	}
}
void Union(int a,int b){
    
    
	int fA = findfather(a);
	int fB = findfather(b);
	if(fA!=fB){
    
    
		father[fA] = fB;
	}
}
int calcu(int N){
    
    
	set<int> s;
	for(int i=0;i<N;i++){
    
    
		father[i] = i;
	}
	for(int i=0;i<N;i++){
    
    
		if(!hashT[i]){
    
    
			for(int j=0;j<G[i].size();j++){
    
    
				int v = G[i][j];
				if(!hashT[v]){
    
    
					Union(i,v);
				}
			} 
		}
	}
	for(int i=0;i<N;i++){
    
    
		if(!hashT[i]){
    
    
			s.insert(findfather(i));
		}
	} 
	int ans = s.size();
	return ans; 
}
int main(){
    
    
	int N,M;
	cin >> N >> M;
	
	for(int i=1;i<=M;i++){
    
    
		int u,v;
		cin >> u >> v;
		G[u].push_back(v);
		G[v].push_back(u); 
	}
	int K;
	cin >> K;
	for(int i=1;i<=K;i++){
    
    
		cin >> a[i];
	} 
	int start = calcu(N);
	for(int i=1;i<=K;i++){
    
    
		hashT[a[i]] = true;
		int tmp = calcu(N);
		if(tmp<=start){
    
    
			printf("City %d is lost.\n",a[i]);
		}else{
    
    
			printf("Red Alert: City %d is lost!\n",a[i]);
		}
		start = tmp;
	}
	if(K==N){
    
    
		printf("Game Over.\n");
	}
	
	return 0;
} 

L2-014 列车调度 (25 分)

算法标签: 单调队列
注意点: 一道好题!这道题思维难度比较大,但是代码量相对较少
首先我们分析一下题目,题目中要求火车出站的序列是单调递减的,也就是说编号较大的火车应该停靠在站台的前端,而编号较小的火车应该停靠在站台的后端,等到编号大的火车出站之后,编号小的自然排在了队头,这样即可满足出站的要求
仔细回想一下所学过的数据结构,发现单调队列正好满足这个要求,队列中总是保存着较小的编号,因此第一种方法就形成了,建立若干个单调队列,每个队列记录最小的编号,然后每次新来的火车,通过二分查找,找到最小编号最接近的站台,排在其后面,并更新该单调队列的记录,此方法可行,但还有更好的方案
纵观上一个方法,尽管我们需要维护若干个单调队列,但是,单调队列无需保存所有火车的编号,而只需要保存其中序列最小的那个即可,因此,可把每个队列抽象成一个数,这个数代表了能够进站的火车最大编号,所有小于这个数的火车被允许进站,排在其位置之后,并更新编号,编号的变化具有单调性(递减),而二分查找可替换成平衡树上查找,因此,我们引入一个集合set,用lower_bound二分查找,用insert快速插入,效率最高!

#include<bits/stdc++.h>
using namespace std;
set<int> s;
int main(){
    
    
	int N;
	scanf("%d",&N);
	for(int i=1;i<=N;i++){
    
    
		int t;
		scanf("%d",&t);
		set<int>::iterator it;
		it = s.lower_bound(t);
		if(it!=s.end()){
    
    
			s.erase(it);
			s.insert(t);
		}else{
    
    
			s.insert(t);
		}
	}
	int ans = s.size();
	cout << ans << endl;
	return 0;
} 

L2-015 互评成绩 (25 分)

算法标签: 排序
注意点: 先对每个人的部分成绩进行排序,然后去掉最高分和最低分,取平均值计算,得到个人最终成绩,最后对所有人的成绩进行排序,输出前M个即可

#include<bits/stdc++.h>
using namespace std;
double ans[10005];
int a[15];
int main(){
    
    
	int N,K,M;
	scanf("%d%d%d",&N,&K,&M);
	for(int i=1;i<=N;i++){
    
    
		for(int j=1;j<=K;j++){
    
    
			scanf("%d",&a[j]);
		} 
		sort(a+1,a+1+K);
		double ave = 0.0;
		for(int j=2;j<=K-1;j++){
    
    
			ave += a[j];
		}
		ave /= (K-2);
		ans[i] = ave;
	}
	sort(ans+1,ans+1+N);
	for(int i=N-M+1;i<=N;i++){
    
    
		if(i!=N){
    
    
			printf("%.3lf ",ans[i]);
		}else{
    
    
			printf("%.3lf\n",ans[i]);
		}
	}
	return 0;
}

L2-016 愿天下有情人都是失散多年的兄妹 (25 分)

算法标签: 并查集 + BFS/DFS
注意点: 首先,考虑到这道题的数据结构不是一棵树,因为找不到公共的祖先源点(根结点不唯一,是森林),因此采用并查集将所有祖先关系都合并起来(祖先关系不同源的人无需判断5层)
接着,有K组输入(题目中未给出K的大小,实际测试结果来看,大约100组数据左右,因为若K很大,BFS/DFS都是超时的算法,需考虑倍增LCA),每组输入给出2个编号,首先判断2个编号的性别,如果一样,输出Never Mind,否则再判断是否同源,若不是,则输出Yes,若是,继续判断5代以内是否有交集,由于题目中说了,给的数据都是同辈份的,这里就省略了需将结点提升到同一层的步骤(倍增LCA),可直接将ID1编号用BFS算法遍历5个层次,把每个层次遍历过的结点都打上已访问的标签,再进行ID2编号,若在5个层次内访问到了已打过标签的结点,则输出No,否则输出Yes

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
int hashT[maxn];
int father[maxn];
vector<int> G[maxn];
bool vis[maxn];

int findfather(int x){
    
    
	if(x==father[x]){
    
    
		return x;
	}else{
    
    
		int F = findfather(father[x]);
		father[x] = F;
		return F;	
	}
}
void Union(int a,int b){
    
    
	int fA = findfather(a);
	int fB = findfather(b);
	if(fA!=fB){
    
    
		father[fA] = fB;
	}
}
void BFS(int u){
    
    
	queue<pair<int,int> > q;
	q.push(make_pair(u,1));
	vis[u] = true;
	while(!q.empty()){
    
    
		pair<int,int> f = q.front();
		q.pop();
		int u = f.first;
		int layer = f.second;
		if(layer<5){
    
    
			for(int i=0;i<G[u].size();i++){
    
    
				int v = G[u][i];
				if(!vis[v]){
    
    
					vis[v] = true;
					q.push(make_pair(v,layer+1));
				}
			}
		}
	}
}
int Check(int u){
    
    
	queue<pair<int,int> > q;
	q.push(make_pair(u,1));
	vis[u] = true;
	while(!q.empty()){
    
    
		pair<int,int> f = q.front();
		q.pop(); 
		int u = f.first;
		int layer = f.second;
		if(layer<5){
    
    
			for(int i=0;i<G[u].size();i++){
    
    
				int v = G[u][i];
				if(!vis[v]){
    
    
					vis[v] = true;
					q.push(make_pair(v,layer+1));
				}else{
    
    
					return 0;
				} 
			}
		}
	}
	return 1;
} 
int main(){
    
    
	for(int i=0;i<maxn;i++){
    
    
		father[i] = i;
	}
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
    
    
		int id;
		scanf("%d",&id);
		char sex;
		cin >> sex;
		if(sex == 'M'){
    
    
			hashT[id] = 1;
		}else{
    
    
			hashT[id] = 2;
		}
		int mid,fid;
		scanf("%d%d",&fid,&mid);
		if(fid!=-1){
    
    
			G[id].push_back(fid);
			Union(id,fid);
			hashT[fid] = 1;
		}
		if(mid!=-1){
    
    
			G[id].push_back(mid);
			Union(id,mid);
			hashT[mid] = 2;
		}
	}
	int K;
	scanf("%d",&K);
	for(int i=1;i<=K;i++){
    
    
		int id1,id2;
		scanf("%d%d",&id1,&id2);
		if(hashT[id1] == hashT[id2]){
    
    
			printf("Never Mind\n"); 
		}else{
    
    
			int f1 = findfather(id1);
			int f2 = findfather(id2);
			if(f1 == f2){
    
    
				memset(vis,0,sizeof(vis));
				BFS(id1);
				int f = Check(id2);
				if(f == 1){
    
    
					printf("Yes\n");
				}else{
    
    
					printf("No\n");
				}
			}else{
    
    
				printf("Yes\n");
			}	
		}
	}
	return 0;
}

L2-017 人以群分 (25 分)

算法标签: 排序
注意点: 先对输入的序列进行排序,然后划分前N/2个为内向型集合,后N-N/2个为外向型集合,两个集合之差即为Diff

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
int a[maxn];
int main(){
    
    
	int N;
	scanf("%d",&N);
	for(int i=1;i<=N;i++){
    
    
		scanf("%d",&a[i]);
	}
	sort(a+1,a+N+1);
	int N1,N2;
	if(N%2){
    
    
		N1 = N/2 +1 ;
		N2 = N-N1;
	}else{
    
    
		N1 = N2 = N/2;
	}
	printf("Outgoing #: %d\n",N1);
	printf("Introverted #: %d\n",N2);
	int ans = 0;
	for(int i=N-N1+1;i<=N;i++){
    
    
		ans += a[i];
	}
	for(int i=1;i<=N2;i++){
    
    
		ans -= a[i];
	}
	printf("Diff = %d\n",ans);
	return 0;
}

L2-018 多项式A除以B (25 分)

算法标签: 高精
注意点: 本题的算法和高精除法一致,模拟竖式相除即可,坑点有如下几个:
(1)本题未标注数据范围,题目保证所有指数是各不相同的非负整数,所有系数是非零整数,所有整数在整型范围内。
这句话本身是有问题的,如果指数e无限大(int上界),无法存储多项式(空间溢出),如果系数无限大,每一轮乘除过后误差不断累积,最终会使得15位有效数字的double不再精确,当误差超过0.05时,那么也无法完成多项式相除的功能(输出结果错误)
事实上,本题的数据比较水,最大的数据指数<3000,项数<3000,因此,除法最多3000次就能完成,算法复杂度 O ( n 2 ) O(n^2) O(n2)即可
(2)零多项式是一个特殊多项式,对应输出为0 0 0.0,这个条件必须特判,测试点1/3/4会出现商或者余数是零多项式的情况
(3)舍入是什么:题目中说,多项式其实有常数项-1/27,但因其舍入后为0.0,这个例子还不够特殊,我们看输出样例:
3 2 0.3 1 0.2 0 -1.0,即
0.3 x 2 + 0.2 x − 1.0 0.3x^2+0.2x-1.0 0.3x2+0.2x1.0
我们用竖式除法计算得到,商是 1 3 x 2 + 2 9 x − 26 27 \frac{1}{3}x^2+\frac{2}{9}x-\frac{26}{27} 31x2+92x2726
− 26 27 = − 0.96 -\frac{26}{27}=-0.96 2726=0.96,答案输出为-1.0,这里就解释的很清楚了,舍入指的是对于小数点后1位进行四舍五入,因此用%.1lf的截断肯定错误,那么如何舍入呢?这里采用的是先将其扩大10倍,取整,四舍五入后,再除以10,还原成小数,对应于下面的convert函数

#include<bits/stdc++.h>
using namespace std;
const int maxn = 3e3+5;
double a[maxn];
double b[maxn];
double c[maxn]; 
double convert(double s){
    
    
	s *= 10;
	int res = (round)(s);
	double ans = res*1.0/10.0;
	return ans;
}
int main(){
    
    
	int N;
	scanf("%d",&N);
	int max1 = -1;
	int max2 = -1;
	for(int i=1;i<=N;i++){
    
    
		int e,coff;
		scanf("%d%d",&e,&coff);
		a[e] = coff*1.0;
		max1 = max(max1,e);
	} 
	scanf("%d",&N);
	for(int i=1;i<=N;i++){
    
    
		int e,coff;
		scanf("%d%d",&e,&coff);
		b[e] = coff*1.0;
		max2 = max(max2,e);
	}
	for(int i=max1;i>=max2;i--){
    
    
		if(fabs(a[i])>1e-3){
    
    
			double t = a[i]/b[max2];
			c[i-max2] += t;
			for(int j=max2;j>=0;j--){
    
    
				if(fabs(b[j])>1e-3){
    
    
					a[i-max2+j] -= (t*b[j]);
				}
			}
		}
	}
	int ans1 = 0;
	for(int i=max1-max2;i>=0;i--){
    
    
		double t = convert(c[i]);
		if(fabs(t)>1e-2){
    
    
			ans1++;
		}
	}
	printf("%d",ans1);
	if(ans1){
    
    
		for(int i=max1-max2;i>=0;i--){
    
    
			double t = convert(c[i]);
			if(fabs(t)>1e-2){
    
    
				printf(" %d %.1lf",i,t);
			} 
		}	
	}else{
    
    
		printf(" 0 0.0");
	}
	
	printf("\n");
	int ans2 = 0;
	for(int i=max2-1;i>=0;i--){
    
    
		double t = convert(a[i]);
		if(fabs(t)>1e-2){
    
    
			ans2++;
		}
	}
	printf("%d",ans2);
	if(ans2){
    
    
		for(int i=max2-1;i>=0;i--){
    
    
			double t = convert(a[i]);
			if(fabs(t)>1e-2){
    
    
				printf(" %d %.1lf",i,t);
			}
		}	
	}else{
    
    
		printf(" 0 0.0");
	}
	
	return 0;
}

L2-019 悄悄关注 (25 分)

算法标签: 哈希
注意点: 先建立一个集合用于查询输入的名字,然后计算平均值,线性扫描并统计后按字典序排序输出

#include<bits/stdc++.h>
using namespace std;
set<string> s;
struct node{
    
    
	string name;
	int v;
};
node stu[10005];
string ans[10005];
int main(){
    
    
	int N;
	cin >> N;
	for(int i=1;i<=N;i++){
    
    
		string t;
		cin >> t;
		s.insert(t);
	}
	int M;
	cin >> M;
	double ave = 0.0;
	for(int i=1;i<=M;i++){
    
    
		cin >> stu[i].name >> stu[i].v;
		ave += stu[i].v;
	}
	ave /= M;

	int cnt = 0;
	for(int i=1;i<=M;i++){
    
    
		if(stu[i].v>ave && s.find(stu[i].name)==s.end()){
    
    
			ans[cnt++] = stu[i].name;
		}
	}
	sort(ans,ans+cnt);
	if(!cnt){
    
    
		cout << "Bing Mei You"  << endl;
	}else{
    
    
		for(int i=0;i<cnt;i++){
    
    
			cout << ans[i] << endl;
		}
	}
	return 0;
}

L2-020 功夫传人 (25 分)

算法标签: 树,二叉树 + 遍历
注意点: 本题考察树的层次遍历,需注意测试点1的特殊情况,即祖师爷也是得道者,初始化的功力应该加倍!

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
vector<int> G[maxn];
int hashT[maxn];
bool vis[maxn];
int N;
double Z,r;
double ans = 0.0;
void levelorder(int S){
    
    
	queue<pair<int,double>> q;
	if(hashT[S]){
    
    
		q.push(make_pair(S,Z*hashT[S]));
	}else{
    
    
		q.push(make_pair(S,Z));
	}
	vis[S] = true;
	while(!q.empty()){
    
    
		pair<int,double> f = q.front();
		q.pop();
		int u = f.first;
		double value = f.second;
		if(hashT[u]){
    
    
			ans += value;
		}
		for(int i=0;i<G[u].size();i++){
    
    
			int v = G[u][i];
			if(!vis[v]){
    
    
				if(hashT[v]){
    
    
					double temp = (100.0-r)/100.0 * value;
					temp = 1.0*temp*hashT[v];
					q.push(make_pair(v,temp));
					vis[v] = true;
				}else{
    
    
					double temp = (100.0-r)/100.0 * value;
					q.push(make_pair(v,temp));
					vis[v] = true;
				}	
			}
		}
	}
	long long res = (long long)ans;
	cout << res << endl;
}
int main(){
    
    
	cin >> N >> Z >> r;
	for(int i=1;i<=N;i++){
    
    
		int K;
		cin >> K;
		if(K==0){
    
    
			int M;
			cin >> M;
			hashT[i-1] = M;
		}else{
    
    
			for(int j=1;j<=K;j++){
    
    
				int v;
				cin >> v;
				G[i-1].push_back(v);
			}
		}
	}
	
	levelorder(0);
	return 0;
}

L2-021 点赞狂魔 (25 分)

算法标签: 哈希 + 排序
注意点: 用哈希方法统计不同标签的个数,然后结构体排序输出结果

#include<bits/stdc++.h>
using namespace std;
struct node{
    
    
	string s;
	int sum = 0;
	double ave = 0.0;
};
node stu[105];
bool cmp(node stu1,node stu2){
    
    
	if(stu1.sum!=stu2.sum){
    
    
		return stu1.sum > stu2.sum;
	}else{
    
    
		return stu1.ave < stu2.ave;
	}
}
int main(){
    
    
	int N;
	cin >> N;
	for(int i=1;i<=N;i++){
    
    
		cin >> stu[i].s;
		int K;
		cin >> K;
		set<int> s;
		for(int j=1;j<=K;j++){
    
    
			int t;
			cin >> t;
			s.insert(t);
		}
		int cnt =  s.size();
		stu[i].sum = cnt;
		stu[i].ave = K*1.0/cnt;
	}
	sort(stu+1,stu+1+N,cmp);
	if(N<3){
    
    
		for(int i=1;i<=N;i++){
    
    
			if(i==1){
    
    
				cout << stu[i].s;
			}else{
    
    
				cout << " " << stu[i].s;
			}
		}
		for(int i=1;i<=3-N;i++){
    
    
			cout << " " << "-";
		}
	}else{
    
    
		for(int i=1;i<=3;i++){
    
    
			if(i==1){
    
    
				cout << stu[i].s; 
			}else{
    
    
				cout << " " << stu[i].s;
			}
		}	
	}
	
	return 0;
}

L2-022 重排链表 (25 分)

算法标签: 链表 + 模拟
注意点: 一道关于链表的模拟题,分奇偶交错排列即可,难度不大,注意测试点3,这种情况下给出N个结点,但可连接成链表的结点数少于N个,因此需重新统计真正的结点个数,然后再进行计算!

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
int address[maxn];
int nex[maxn];
int value[maxn];
int ans_add[maxn];
int ans_next[maxn];
int ans_value[maxn];
int main(){
    
    
	int S;
	cin >> S;
	int N;
	cin >> N;
	for(int i=1;i<=N;i++){
    
    
		int add;
		cin >> add;
		cin >> value[add] >> nex[add];
	}
	int t = S;
	int NL = 0;
	while(t!=-1){
    
    
		NL++;
		t = nex[t];
	}
	int N0 = NL/2;
	int cnt = 1;
	t = S;
	while(t!=-1){
    
    
		if(cnt<=N0){
    
    
			ans_value[cnt*2] = value[t];
			ans_add[cnt*2] = t;
		}else{
    
    
			int temp = (cnt-N0);
			temp = temp*2-1;
			if(NL%2==0){
    
    
				temp = NL-temp;
			}else{
    
    
				temp = NL-temp+1;
			}
			ans_value[temp] = value[t];
			ans_add[temp] = t;
		}
		cnt++;
		t = nex[t];
	}
	for(int i=1;i<=NL-1;i++){
    
    
		ans_next[i] = ans_add[i+1];
	}
	ans_next[NL] = -1;
	for(int i=1;i<=NL-1;i++){
    
    
		printf("%05d %d %05d\n",ans_add[i],ans_value[i],ans_next[i]);
	}
	printf("%05d %d %d\n",ans_add[NL],ans_value[NL],-1);
	return 0;
}

L2-023 图着色问题 (25 分)

算法标签: 图论 + 染色
注意点: 图染色的判断问题,首先是要判断颜色的数目,题目要求用K种颜色进行染色,也就是说,必须使用K种颜色,大于或小于都是不允许的,然后用K种颜色染色,保证无向图中,任意一条边的两个结点都是不同的颜色,最后输出判断的结果

#include<bits/stdc++.h>
using namespace std;

vector<int> G[505];
int a[505];
int main(){
    
    
	int V,E,K;
	cin >> V >> E >> K;
	for(int i=1;i<=E;i++){
    
    
		int u,v;
		cin >> u >> v;
		G[u].push_back(v);
		G[v].push_back(u); 
	}
	int N;
	cin >> N;
	for(int i=1;i<=N;i++){
    
    
		for(int j=1;j<=V;j++){
    
    
			cin >> a[j];
		}
		bool f = false;
		set<int> s;
		for(int j=1;j<=V;j++){
    
    
			s.insert(a[j]);
		}
		if(s.size()!=K){
    
    
			printf("No\n");
		}else{
    
    
			for(int u=1;u<=V;u++){
    
    
				for(int j=0;j<G[u].size();j++){
    
    
					int v = G[u][j];
					if(a[u]!=a[v]){
    
    
						continue;
					}else{
    
    
						f = true;
						break;
					}
				}
				if(f){
    
    
					break;
				}
			}
			if(f){
    
    
				printf("No\n");
			}else{
    
    
				printf("Yes\n");
			}
		}
	}
	return 0;
} 

L2-024 部落 (25 分)

算法标签: 并查集
注意点: 并查集模板题,具体可参考数据结构专题系列-并查集篇

#include<bits/stdc++.h>
using namespace std;
const int maxn = 10005;
int father[maxn];
int a[maxn];
int findfather(int x){
    
    
	if(x==father[x]){
    
    
		return x;
	}else{
    
    
		int F = findfather(father[x]);
		father[x] = F;
		return F;	
	}
}
void Union(int a,int b){
    
    
	int fA = findfather(a);
	int fB = findfather(b);
	if(fA!=fB){
    
    
		father[fA] = fB;
	}
}
set<int> s;
int main(){
    
    
	int N;
	cin >> N;
	for(int i=1;i<=10000;i++){
    
    
		father[i] = i;
	}
	for(int i=1;i<=N;i++){
    
    
		int K;
		cin >> K;
		for(int j=1;j<=K;j++){
    
    
			cin >> a[j];
			s.insert(a[j]);
		}
		for(int j=2;j<=K;j++){
    
    
			Union(a[1],a[j]);
		}
	}
	set<int> s2;
	for(auto it=s.begin();it!=s.end();it++){
    
    
		int t = *it;
		s2.insert(findfather(t));
	}
	int ans1 = s.size();
	int ans2 = s2.size();
	cout << ans1 << " " << ans2 << endl;
	int Q;
	cin >> Q;
	for(int i=1;i<=Q;i++){
    
    
		int u,v;
		cin >> u >> v;
		int fx = findfather(u);
		int fy = findfather(v);
		if(fx!=fy){
    
    
			cout << "N" << endl;
		}else{
    
    
			cout << "Y" << endl;
		}
	}
	return 0;
} 

L2-025 分而治之 (25 分)

算法标签: 图论 + 枚举
注意点: 枚举每个未被占领的顶点,判断是否连通即可!此处的连通是指不与任何城市有边连通,即孤立的顶点

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e4+5;
bool hashT[maxn];
vector<int> G[maxn];
int main(){
    
    
	int N,M;
	cin >> N >> M;
	for(int i=1;i<=M;i++){
    
    
		int u,v;
		cin >> u >> v;
		G[u].push_back(v);
		G[v].push_back(u);
	}
	int K;
	cin >> K;
	for(int i=1;i<=K;i++){
    
    
		memset(hashT,0,sizeof(hashT));
		int NP;
		cin >> NP;
		for(int i=1;i<=NP;i++){
    
    
			int t;
			cin >> t;
			hashT[t] = true;
		}
		bool f = true;
		for(int i=1;i<=N;i++){
    
    
			if(hashT[i]){
    
    
				continue;
			}else{
    
    
				for(int j=0;j<G[i].size();j++){
    
    
					int v = G[i][j];
					if(!hashT[v]){
    
    
						f = false;
						break;
					}
				}
				if(!f){
    
    
					break;
				}
			}
		}
		if(f){
    
    
			cout << "YES" << endl;
		}else{
    
    
			cout << "NO" << endl;
		}
	}
		
	
	return 0;
}

L2-026 小字辈 (25 分)

算法标签: 树,二叉树 + 遍历
注意点: 本题考察树的层次遍历,求树中最深结点的深度,并输出最底层叶结点的值

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
int layer[maxn];
bool vis[maxn];
vector<int> G[maxn];
void levelorder(int root){
    
    
	queue<int> q;
	vis[root] = true;
	q.push(root);
	while(!q.empty()){
    
    
		int f = q.front(); 
		q.pop();
		for(int i=0;i<G[f].size();i++){
    
    
			int v = G[f][i];
			if(!vis[v]){
    
    
				vis[v] = true;
				layer[v] = layer[f] + 1;
				q.push(v);
			}
		}
	}
}
int main(){
    
    
	int N;
	scanf("%d",&N);
	int root = 0;
	for(int i=1;i<=N;i++){
    
    
		int t;
		scanf("%d",&t);
		if(t==-1){
    
    
			root = i;
			layer[root] = 1;
		}else{
    
    
			G[t].push_back(i);
		}
	}
	levelorder(root);
	int maxm = -1;
	for(int i=1;i<=N;i++){
    
    
		maxm = max(maxm,layer[i]);
	}
	cout << maxm << endl;
	int cnt = 0;
	for(int i=1;i<=N;i++){
    
    
		if(layer[i] == maxm){
    
    
			if(!cnt){
    
    
				cout << i;
			}else{
    
    
				cout << " " << i;
			}
			cnt++;
		}
	}
	return 0;
} 

L2-027 名人堂与代金券 (25 分)

算法标签: 排序
注意点: 需注意输出排名前K名的成绩单,由于存在并列的可能性,因此输出不一定是K个人

#include<bits/stdc++.h>
using namespace std;
struct node{
    
    
	string s;
	int score;
	int rank;
};
const int maxn = 1e4+5;
node stu[maxn];
bool cmp(node stu1,node stu2){
    
    
	if(stu1.score!=stu2.score){
    
    
		return stu1.score>stu2.score;
	}else{
    
    
		return stu1.s < stu2.s;
	}
}
int main(){
    
    
	int N,G,K;
	cin >> N >> G >> K;
	int ans = 0;
	for(int i=1;i<=N;i++){
    
    
		cin >> stu[i].s >> stu[i].score;
		if(stu[i].score>=G){
    
    
			ans += 50;	
		}else if(stu[i].score>=60){
    
    
			ans += 20;
		} 
	}
	cout << ans << endl;
	sort(stu+1,stu+1+N,cmp);
	stu[1].rank = 1;
	for(int i=2;i<=N;i++){
    
    
		if(stu[i].score == stu[i-1].score){
    
    
			stu[i].rank = stu[i-1].rank;
		}else{
    
    
			stu[i].rank = i;
		}
	}
	for(int i=1;i<=N;i++){
    
    
		if(stu[i].rank<=K){
    
    
			cout << stu[i].rank << " " << stu[i].s << " " << stu[i].score << endl;
		}else{
    
    
			break;
		}
	}
	return 0;
}

L2-028 秀恩爱分得快 (25 分)

算法标签: 字符串 + 枚举
注意点: 做这道题之前,可以先看这道题:PAT甲级 1139 First Contact (30 分),具体可从[OJ题解系列 目录导航帖]获得
本题难度比那道题略小,坑点数量也少一些,由于可能出现+0与-0元素,-代表女生,+代表男生,因此读入的时候,用字符串读入,再转换成整数,输出时也注意+0与-0的输出
此外,输出A和B的条件为:当且仅当与A最亲密的异性是B,与B最亲密的异性是A,若两者其一不满足,那么就分别输出A最亲密的和B最亲密的

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e3+5;
int hashT[maxn];
int a[maxn];
double G[maxn][maxn];
int main(){
    
    
	int N,M;
	scanf("%d%d",&N,&M);
	for(int i=1;i<=M;i++){
    
    
		int K;
		scanf("%d",&K);
		for(int j=1;j<=K;j++){
    
    
			char s[6];
			scanf("%s",s);
			int number = 0;
			if(s[0] == '-'){
    
    
				for(int i=1;i<strlen(s);i++){
    
    
					number = number*10 + s[i]-'0';
				}
				hashT[number] = 2;
			}else{
    
    
				for(int i=0;i<strlen(s);i++){
    
    
					number = number*10 + s[i] -'0';
				}
				hashT[number] = 1;
			}
			a[j] = number;
		}
		double T = 1.0/K;
		for(int j=1;j<=K-1;j++){
    
    
			for(int k=j+1;k<=K;k++){
    
    
				G[a[j]][a[k]] += T;
				G[a[k]][a[j]] += T;
			}
		}
	}
	string sA,sB;
	cin >> sA >> sB;
	int f1 = 0,f2 = 0;
	int A = 0,B = 0;
	if(sA[0]=='-'){
    
    
		f1 = 2;
		for(int i=1;i<sA.size();i++){
    
    
			A = A*10 + sA[i]-'0';
		}
	}else{
    
    
		f1 = 1;
		for(int i=0;i<sA.size();i++){
    
    
			A = A*10 + sA[i] - '0';
		}
	}
	if(sB[0]=='-'){
    
    
		f2 = 2;
		for(int i=1;i<sB.size();i++){
    
    
			B = B*10 + sB[i] - '0';
		}
	}else{
    
    
		f2 = 1;
		for(int i=0;i<sB.size();i++){
    
    
			B = B*10 + sB[i] - '0';
		}
	}
	
	double maxA = -1.0; 
	double maxB = -1.0;
	
	for(int i=0;i<N;i++){
    
    
		if(((f1==2 && hashT[i]==1) || (f1==1 && hashT[i]==2)) && G[A][i]>maxA){
    
    
			maxA = G[A][i];
		}
	}
	for(int i=0;i<N;i++){
    
    
		if(((f2==2 && hashT[i]==1) || (f2==1 && hashT[i]==2)) && G[B][i]>maxB){
    
    
			maxB = G[B][i];
		}
	}
	double ans = G[A][B];
	
	if((fabs(ans-maxA)<1e-5 && fabs(ans-maxB)<1e-5)){
    
    
		cout << sA << " " << sB << endl;
	}else{
    
    
		for(int i=0;i<N;i++){
    
    
			if((f1==2 && hashT[i]==1) && fabs(G[A][i]-maxA)<1e-4){
    
    
				if(A==0){
    
    
					printf("-0 %d\n",i);
				}else{
    
    
					printf("%d %d\n",-A,i);
				}
			}else if((f1==1 && hashT[i]==2) && fabs(G[A][i]-maxA)<1e-4){
    
    
				if(i==0){
    
    
					printf("%d -0\n",A);
				}else{
    
    
					printf("%d %d\n",A,-i);
				}	
			}
		}
		for(int i=0;i<N;i++){
    
    
			if((f2==2 && hashT[i]==1) && fabs(G[B][i]-maxB)<1e-4){
    
    
				if(B==0){
    
    
					printf("-0 %d\n",i);
				}else{
    
    
					printf("%d %d\n",-B,i);
				}
			}else if((f2==1 && hashT[i]==2) && fabs(G[B][i]-maxB)<1e-4){
    
    
				if(i==0){
    
    
					printf("%d -0\n",B);
				}else{
    
    
					printf("%d %d\n",B,-i);
				}
			}
		}
	}
	return 0;
}

L2-029 特立独行的幸福 (25 分)

算法标签: 数论 + 模拟
注意点: 按照题目所给的条件模拟即可
(1)注意进入无限循环的判断,当出现了重复元素后,就退出迭代
(2)注意判断数字的“独立性”,将每个数迭代后,到1结束之间的所有数,都用哈希表记录下,未被记录过的数字一定是满足“独立性”的

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e4+5;
int a[maxn];
bool hashT[maxn];
int ans[maxn];
int calcu(int N){
    
    
	int ans = 0;
	while(N){
    
    
		int u = N%10;
		ans += u*u;
		N /=10;
	}
	return ans;
}
bool isprime(int N){
    
    
	if(N<2){
    
    
		return 0;
	}
	for(int i=2;i<=sqrt(N);i++){
    
    
		if(N%i==0){
    
    
			return 0;
		}
	}
	return 1;
}
int main(){
    
    
	int A,B;
	cin >> A >> B;
	for(int i=A;i<=B;i++){
    
    
		int t = i;
		set<int> s;
		while(t!=1){
    
    
			t = calcu(t);
			if(s.find(t) != s.end()){
    
    
				break;
			}else{
    
    
				s.insert(t);
			}
		}
		if(t == 1){
    
    
			for(auto it=s.begin();it!=s.end();it++){
    
    
				int u = *it;
				hashT[u] = true;
			}
			ans[i] = s.size();
		}
	}
	int cnt = 0;
	for(int i=A;i<=B;i++){
    
    
		if(!hashT[i] && ans[i]){
    
    
			cnt++;
			if(isprime(i)){
    
    
				printf("%d %d\n",i,2*ans[i]);
			}else{
    
    
				printf("%d %d\n",i,ans[i]);
			}
		}
	}
	if(!cnt){
    
    
		cout << "SAD" << endl;
	} 
	
	return 0;
}

L2-030 冰岛人 (25 分)

算法标签: LCA + BFS/DFS
注意点: 一道很坑的题目!
本题存在很多细节以及理解上的误差(题面表述不清晰):
(1)维京人后裔是可以通过姓的后缀判断其性别的,其他人则是在姓的后面加 m 表示男性、f 表示女性。这句话表明带有m/f的后缀既有可能是维京人的祖先,也有可能是不是维京人。
(2)题目保证给出的每个维京家族的起源人都是男性。这句话表明只有m可能是维京人的祖先,f则不是维京人,因此,m/f都没有上一代,在树上无需建立边,而其余情况需建立从child到parent的边(代码中vis数组记录无需建立边的情况,[测试点2]/[测试点4])
(3)题目保证不存在两个人是同名的,这意味着用名做key进行哈希查找
(4)接下来看题面的输出条件:
对每一个查询,根据结果在一行内显示以下信息:
1.若两人为异性,且五代以内无公共祖先,则输出 Yes;
2.若两人为异性,但五代以内(不包括第五代)有公共祖先,则输出 No;
3.若两人为同性,则输出 Whatever;(这里直接判断性别即可,外层if条件判断)
4.若有一人不在名单内,则输出 NA。(任意一个名字哈希查找失败,外层if条件判断)
3、4条件容易判断,1、2条件表述模糊,题目还补充了这么一个条件:
所谓“五代以内无公共祖先”是指两人的公共祖先(如果存在的话)必须比任何一方的曾祖父辈分高。
也就是说,要先找到公共祖先,然后判断该公共祖先不在任一个人的五代以内,比方说,LCA比A高9层,比B高3层,还是在五代以内,应该输出No,此时,我们再回看条件1、2,发现有表述不严谨之处,所谓五代以内,是指层次较高的结点五代以内没有公共祖先,对于层次较低的结点,可以理解为N代内无公共祖先(不限制5层,[测试点3]/[测试点6])

#include<bits/stdc++.h>
using namespace std;
map<string,int> mp1;
map<int,string> mp2;
map<string,int> sex;
const int maxn = 2e5+5;
string C1[maxn];
string C2[maxn];
bool vis[maxn];
vector<int> G[maxn];

int cnt = 0;
int check(int u1,int u2){
    
    
	vector<int> v1;
	v1.push_back(u1);
	vector<int> v2;
	v2.push_back(u2); 
	int t1 = G[u1].size();
	while(t1){
    
    
		v1.push_back(G[u1][0]);
		u1 = G[u1][0];
		t1 = G[u1].size();
	}
	int t2 = G[u2].size();
	while(t2){
    
    
		v2.push_back(G[u2][0]);
		u2 = G[u2][0];
		t2 = G[u2].size();
	}
	if(v1.back() == v2.back()){
    
    
		int size1 = v1.size();
		int size2 = v2.size();
		while(size1>0 && size2>0 && v1[size1-1] == v2[size2-1]){
    
    
			size1--;
			size2--;
		}
		size1++;
		size2++;
		if(size1>=5 && size2>=5){
    
    
			return 1;
		}else{
    
    
			return 0;
		}
	}else{
    
    
		return 1;
	}
}

int main(){
    
    
	int N;
	scanf("%d",&N);
	for(int i=1;i<=N;i++){
    
    
		string s2,s1;		//s2-name,s1-surname
		cin >> s2 >> s1;
		int len1 = s1.size();
		string first;
		if(mp1.find(s2)==mp1.end()){
    
    
			mp1[s2] = ++cnt;
			mp2[cnt] = s2;
		}
		if(s1[len1-1] == 'm'){
    
    
			first = s1.substr(0,len1-1);
			sex[s2] = 1;
			vis[mp1[s2]] = true;
		}else if(s1[len1-1] == 'f'){
    
    
			first = s1.substr(0,len1-1);
			sex[s2] = 2;
            vis[mp1[s2]] = true;
		}else if(s1.substr(len1-4) == "sson"){
    
    
			first = s1.substr(0,len1-4);
			sex[s2] = 1;
		}else if(s1.substr(len1-7) == "sdottir"){
    
    
			first = s1.substr(0,len1-7);
			sex[s2] = 2;
		}
		if(mp1.find(first)==mp1.end()){
    
    
			mp1[first] = ++cnt;
			mp2[cnt] = first;
		}
		C1[i] = s2;
		C2[i] = first;
	}
	for(int i=1;i<=N;i++){
    
    
		if(!vis[mp1[C1[i]]]){
    
    
			int u = mp1[C1[i]];
			int v = mp1[C2[i]];
			G[u].push_back(v);	
		}
	}
	
	int M;
	scanf("%d",&M);
	for(int i=1;i<=M;i++){
    
    
		string name1,surname1,name2,surname2;
		cin >> name1 >> surname1 >> name2 >> surname2;
		if(mp1.find(name1) == mp1.end() || mp1.find(name2) == mp1.end()){
    
    
			printf("NA\n");
		}else{
    
    
			int t1 = sex[name1];
			int t2 = sex[name2];
			if(t1 == t2){
    
    
				printf("Whatever\n");
			}else{
    
    
				int u1 = mp1[name1];
				int u2 = mp1[name2];
				int op = check(u1,u2);
				if(op){
    
    
					printf("Yes\n");
				}else{
    
    
					printf("No\n");
				}
			}
		}
	} 
	return 0;
}

L2-031 深入虎穴 (25 分)

算法标签: 树,二叉树 + 遍历
注意点: 本题考察的算法为求一棵树的最大深度,这里采用DFS方法记录

#include<bits/stdc++.h>
using namespace std;
int N;
const int maxn = 1e5+5;
vector<int> G[maxn];
bool hashT[maxn];
vector<int> temp;
int ans;
int maxm = -1;
void dfs(int root){
    
    
	temp.push_back(root);
	if(G[root].size()==0){
    
    
		int S = temp.size();
		if(S>maxm){
    
    
			maxm = S;
			ans = root;
		}
	}else{
    
    
		for(int i=0;i<G[root].size();i++){
    
    
			int v = G[root][i];
			dfs(v);
		}
	}
	temp.pop_back();
}
int main(){
    
    
	cin >> N;
	for(int i=1;i<=N;i++){
    
    
		int K;
		cin >> K;
		for(int j=0;j<K;j++){
    
    
			int t;
			cin >> t;
			G[i].push_back(t);
			hashT[t] = true;
		}
	}
	int root = -1;
	for(int i=1;i<=N;i++){
    
    
		if(!hashT[i]){
    
    
			root = i;
			break;
		}
	}
	dfs(root);
	cout << ans << endl;
	
	return 0;
}

L2-032 彩虹瓶 (25 分)

算法标签: 栈混洗
注意点: 本题考察的是栈结构,给你一个序列,并且限制栈的大小,要求判断该序列是否为栈混洗的序列
当入栈元素超过栈大小时,或者是栈内还存在元素(无法取出)时,都是不合法序列,输出NO,其余情况输出YES

#include<bits/stdc++.h>
using namespace std;
int a[1005];
int main(){
    
    
	int N,M,K;
	cin >> N >> M >> K;
	for(int i=1;i<=K;i++){
    
    
		for(int j=1;j<=N;j++){
    
    
			cin >> a[j];
		}
		stack<int> s;
		int cnt = 1;
		bool f = true;
		for(int j=1;j<=N;){
    
    
			if(a[j] == cnt){
    
    
				cnt++;
				j++;
			}else if(!s.empty() && cnt == s.top()){
    
    
				s.pop();
				cnt++;
			}else{
    
    
				s.push(a[j]);
				j++;
				if(s.size()>M){
    
    
					f = false;
					break;
				}
			}
		}
		
		while(!s.empty()){
    
    
			if(s.top() == cnt){
    
    
				cnt++;
				s.pop();
			}else{
    
    
				break;
			}
		}
		if(!s.empty()){
    
    
			f = false;
		}
		if(f){
    
    
			printf("YES\n");
		}else{
    
    
			printf("NO\n");
		}
	} 
	
	return 0;
}

L2-033 简单计算器 (25 分)

算法标签:
注意点: 栈算法模板题,考察了栈的符号算术功能

#include<bits/stdc++.h>
using namespace std;
int a[1005];
stack<int> s1;	
stack<char> s2;
int main(){
    
    
	int N;
	cin >> N;
	for(int i=1;i<=N;i++){
    
    
		int t;
		cin >> t;
		s1.push(t);
	}
	for(int i=1;i<=N-1;i++){
    
    
		char ch;
		cin >> ch;
		s2.push(ch);
	}
	while(!s2.empty()){
    
    
		int n1 = s1.top();
		s1.pop();
		int n2 = s1.top();
		s1.pop();
		char ch = s2.top();
		s2.pop();
		if(ch == '+'){
    
    
			int ans = n2 + n1;
			s1.push(ans);
		}else if(ch == '-'){
    
    
			int ans = n2 - n1;
			s1.push(ans);
		}else if(ch == '*'){
    
    
			int ans = n2 * n1;
			s1.push(ans);
		}else{
    
    
			if(n1==0){
    
    
				printf("ERROR: %d/0",n2);
				exit(0);
			}else{
    
    
				int ans = n2 / n1;
				s1.push(ans);
			}
		}
	}
	cout << s1.top() << endl;
	return 0;
}

L2-034 口罩发放 (25 分)

算法标签: 大模拟 + 排序
注意点: 一道坑题!
由于题意不清,因此理解上可能会有各式各样的问题,首先,梳理一下题目中的各种词汇:
(1)申请信息——每一个数据块给出一天的申请信息、申请信息的每一条记录为申请记录
(2)发放信息——程序输出的发放记录,按照提交时间第一优先级,申请记录顺序第二优先级排序
(3)状况信息——顺序按照申请记录中出现的顺序确定,不重不漏(合法记录指ID号18位,且是数字)
纵观题目的各个条件,我们发现(2)是需要排序的,而(3)是不需要排序的。因此先处理(3),再处理(2)
要确保信息的不重复,则必须采用哈希算法,由于ID号的唯一性,因此用ID作为关键字,建立与name的映射
最后注意一点,ID号必须为18位,且都是数字(不是字符)!

#include<bits/stdc++.h>
using namespace std;
const int maxn = 3e4+5;
struct node{
    
    
	string name;
	string ID;
	int op;
	int h;
	int m;
	int Day;
	int number;
};
node stu[1005];

int hashT[maxn];
bool vis[maxn];
string ans[maxn];
int res = 0;

bool cmp(node stu1,node stu2){
    
    
	if(stu1.h!=stu2.h){
    
    
		return stu1.h < stu2.h;
	}else if(stu1.m!=stu2.m){
    
    
		return stu1.m < stu2.m;
	}else{
    
    
		return stu1.number < stu2.number;
	}
}

map<string,int> mp1;
map<int,string> mp2;
map<string,string> mp3;

int check(string s){
    
    
	for(int i=0;i<s.size();i++){
    
    
		if(s[i]>='0' && s[i]<='9'){
    
    
			continue;
		}else{
    
    
			return 0;
		}
	} 
	return 1;
}
int main(){
    
    
	int D,P;
	scanf("%d%d",&D,&P);
	int cnt = 0;
	for(int i=0;i<maxn;i++){
    
    
		hashT[i] = -100;
	}
	for(int i=1;i<=D;i++){
    
    
		int T,S;
		scanf("%d%d",&T,&S);
		for(int j=1;j<=T;j++){
    
    
			cin >> stu[j].name >> stu[j].ID >> stu[j].op;
			scanf("%d:%d",&stu[j].h,&stu[j].m);
			stu[j].Day = i;
			stu[j].number = j;
			int len = stu[j].ID.size();
			if(len==18 && check(stu[j].ID)){
    
    
				if(mp1.find(stu[j].ID) == mp1.end()){
    
    
					mp1[stu[j].ID] = ++cnt;
					mp2[cnt] = stu[j].ID;
					mp3[stu[j].ID] = stu[j].name;
				}
				int id = mp1[stu[j].ID];
				if(stu[j].op == 1 && !vis[id]){
    
    
					vis[id] = true;
					ans[res++] = stu[j].ID;
				}	
			}
		}
		sort(stu+1,stu+1+T,cmp);
		for(int j=1;j<=T;j++){
    
    
			int len = stu[j].ID.size();
			if(len==18 && check(stu[j].ID)){
    
    
				if(mp1.find(stu[j].ID) == mp1.end()){
    
    
					mp1[stu[j].ID] = ++cnt;
					mp2[cnt] = stu[j].ID;
					mp3[stu[j].ID] = stu[j].name;
				}
				int id = mp1[stu[j].ID];
				int D1 = hashT[id];
				if(stu[j].Day-D1>P && S>0){
    
    
					S--;
					hashT[id] = stu[j].Day;
					cout << stu[j].name << " " << stu[j].ID << endl;
				}
			}
		}
	}
	for(int i=0;i<res;i++){
    
    
		cout << mp3[ans[i]] << " " << ans[i] << endl;
	}
	return 0;
}

L2-035 完全二叉树的层序遍历 (25 分)

算法标签: 树,二叉树 + 遍历
注意点: 一道好题!这里给出了一种新的建树方式,后序遍历建树(完全二叉树),按序输出即为层次遍历的值

#include<bits/stdc++.h>
using namespace std;
int post[35];
int N;
void postorder(int root){
    
    
	if(root>N){
    
    
		return;
	} 
	postorder(root * 2);
	postorder(root * 2 + 1);
	cin >> post[root];
}
int main(){
    
    
	cin >> N;
	postorder(1);
	for(int i=1;i<=N;i++){
    
    
		if(i==1){
    
    
			cout << post[i];
		}else{
    
    
			cout << " " << post[i];
		}
	}
	
	return 0;
}

L2-036 网红点打卡攻略 (25 分)

算法标签: 图论 + 哈密尔顿环路
注意点: 本题考察哈密尔顿环路问题,首先需要判断哈密尔顿环路是否满足(路径连通,且访问每个顶点仅一次),满足条件则统计,并记录最短路径和当前的方案编号

#include<bits/stdc++.h>
using namespace std;
const int maxn = 205;
int G[205][205];
int a[205];
bool hashT[205];
int main(){
    
    
	memset(G,0x3f,sizeof(G));
	int N,M;
	cin >> N >> M;
	for(int i=1;i<=M;i++){
    
    
		int u,v,w;
		cin >> u >> v >> w;
		G[u][v] = G[v][u] = w;
	} 
	int K;
	cin >> K;
	int cnt = 0;
	int maxm = 0x3f3f3f3f;
	int site = -1;
	for(int i=1;i<=K;i++){
    
    
		memset(hashT,0,sizeof(hashT));
		memset(a,0,sizeof(a));
		int n;
		cin >> n;
		for(int j=1;j<=n;j++){
    
    
			cin >> a[j];
			hashT[a[j]] = 1;
		}
		if(n!=N){
    
    
			continue;
		}else{
    
    
			bool f = true;
			for(int i=1;i<=N;i++){
    
    
				if(hashT[i]){
    
    
					continue;
				}else{
    
    
					f = false;
					break;
				}
			}
			if(f){
    
    
				int ans = 0;
				bool f2 = true;
				for(int i=1;i<=N+1;i++){
    
    
					if(G[a[i-1]][a[i]]!=0x3f3f3f3f){
    
    
						ans += G[a[i-1]][a[i]];
					}else{
    
    
						f2 = false;
						break;
					}
				}
				if(f2){
    
    
					cnt++;
					if(ans<maxm){
    
    
						maxm = ans;
						site = i;
					}
				}
			}
		}
	}
	cout << cnt << endl;
	cout << site << " " << maxm << endl;
	return 0;
}

L2-037 包装机 (25 分)

算法标签: 模拟
注意点: 按照题目操作要求模拟包装机的过程,注意栈和队列的判空!

#include<bits/stdc++.h>
using namespace std;
queue<char> q[105];
stack<int> s;
string out = "";
int main(){
    
    
	int N,M,Smax;
	scanf("%d%d%d",&N,&M,&Smax);
	for(int i=1;i<=N;i++){
    
    
		for(int j=1;j<=M;j++){
    
    
			char t;
			cin >> t;
			q[i].push(t);
		}
	}
	int op;
	int cnt = 0;
	while(scanf("%d",&op) && op!=-1){
    
    
		if(op == 0){
    
    
			if(!s.empty()){
    
    
				char t = s.top();
				s.pop();
				out += string(1,t);
				cnt--;
			}
		}else{
    
    
			if(!q[op].empty()){
    
    
				char f = q[op].front();
				q[op].pop();
				if(cnt == Smax){
    
    
					char t = s.top();
					s.pop();
					out += string(1,t);
					s.push(f);
				}else{
    
    
					s.push(f);
					cnt++;
				}
			}
		}
	}
	cout << out << endl;
	return 0;
}

L2-038 病毒溯源 (25 分

算法标签: 树,二叉树 + DFS遍历
注意点: 首先找到根结点root(不是任何子结点的结点一定是根结点),然后从根结点开始执行DFS遍历,即可求出最大深度,输出字典序较小的结果即可

#include<bits/stdc++.h>
using namespace std;
int N;
const int maxn = 1e4+5;
vector<int> G[maxn];
bool hashT[maxn];
vector<int> temp;
vector<int> ans; 
int maxm = -1;
void dfs(int root){
    
    
	temp.push_back(root);
	if(G[root].size()==0){
    
    
		int S = temp.size();
		if(S>maxm){
    
    
			maxm = S;
			ans = temp;
		}else if(S == maxm){
    
    
			if(temp<ans){
    
    
				ans = temp;
			}
		}
	}else{
    
    
		for(int i=0;i<G[root].size();i++){
    
    
			int v = G[root][i];
			dfs(v);
		}
	}
	temp.pop_back();
}
int main(){
    
    
	cin >> N;
	for(int i=0;i<N;i++){
    
    
		int K;
		cin >> K;
		for(int j=0;j<K;j++){
    
    
			int t;
			cin >> t;
			G[i].push_back(t);
			hashT[t] = true;
		}
	}
	int root = -1;
	for(int i=0;i<N;i++){
    
    
		if(!hashT[i]){
    
    
			root = i;
			break;
		}
	}
	dfs(root);
	cout << ans.size() << endl;
	for(int i=0;i<ans.size();i++){
    
    
		if(i==0){
    
    
			cout << ans[i];
		}else{
    
    
			cout << " " << ans[i];
		}
	}
	return 0;
}

L2-039 清点代码库 (25 分)

算法标签: 哈希 + 排序
注意点: 这道题考察哈希算法,我们需要将一串“输出值”,通过哈希函数映射成一个数,从而满足题目中的查询要求,这里采用STL的map容器实现
首先读入不同模块的输入,若该组输入在哈希表中出现过,那么我们只需要将该模块的计数器+1,若没有出现过,那么我们需要在哈希表中建立一个映射,并将模块计数器初始化为1,输入结束后,我们对结构体进行排序,得到最终的答案!

#include<bits/stdc++.h>
using namespace std;
vector<int> V[10005];
struct node{
    
    
	int number;
	int ans = 0;
};
node r[10005];

map<vector<int>,int> mp;
map<int,vector<int> > mp2;
bool cmp(node r1,node r2){
    
    
	if(r1.ans!=r2.ans){
    
    
		return r1.ans > r2.ans;
	}else{
    
    
		vector<int> v1;
		vector<int> v2;
		v1 = mp2[r1.number];
		v2 = mp2[r2.number];
		return v1 < v2;
	}
}
int main(){
    
    
	int N,M;
	scanf("%d%d",&N,&M);
	for(int i=1;i<=N;i++){
    
    
		for(int j=1;j<=M;j++){
    
    
			int t;
			scanf("%d",&t);
			V[i].push_back(t);
		}
	}
	int cnt = 0;
	for(int i=1;i<=N;i++){
    
    
		if(mp.find(V[i])==mp.end()){
    
    
			mp[V[i]] = ++cnt;
			mp2[cnt] = V[i];
			r[cnt].ans = 1;
			r[cnt].number = cnt;
		}else{
    
    
			r[mp[V[i]]].ans++;
		}
	}
	sort(r+1,r+1+cnt,cmp);
	printf("%d\n",cnt);
	for(int i=1;i<=cnt;i++){
    
    
		printf("%d",r[i].ans);
		vector<int> v = mp2[r[i].number];
		for(int j=0;j<v.size();j++){
    
    
			printf(" %d",v[j]);
		}
		printf("\n");
	}
	return 0;
}

L2-040 哲哲打游戏 (25 分)

算法标签: 大模拟
注意点: 本题考察的算法是大模拟,按照题目的要求,模拟游戏的读档、存档操作,哈希数组用来存档,读取也从该数组中取出,注意本题的剧本从1开始

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
int hashT[105];
vector<int> G[maxn];
int main(){
    
    
	int N,M;
	scanf("%d%d",&N,&M);
	for(int i=1;i<=N;i++){
    
    
		int K;
		scanf("%d",&K);
		for(int j=1;j<=K;j++){
    
    
			int t;
			scanf("%d",&t);
			G[i].push_back(t);
		} 
	}
	int start = 1;
	for(int i=1;i<=M;i++){
    
    
		int op,x;
		scanf("%d%d",&op,&x);
		if(op == 0){
    
    
			start = G[start][x-1];
		}else if(op == 1){
    
    
			hashT[x] = start;
			printf("%d\n",start);
		}else{
    
    
			start = hashT[x];
		}
	}
	printf("%d\n",start);
	return 0;
} 

L2-041 插松枝(25分)

算法标签: 模拟 + 队列/栈
注意点: 易知本题考察的是队列/栈,小盒子是栈,推送器是队列
根据题目的要求,我们可以将其分成2个环节处理:推送器上还有小松针/推送器上没有小松针:
(1)推送器上还有小松针:此时先检查盒子内是否有松针,若有,则按要求不超过K个且满足松针大小单调不递增性质依次pop,直至不能pop时,若记录的小松针个数为K个,那么直接输出,否则,依次检查推送器上的小松针,满足要求的加入,直至K个输出;不满足要求的加入小盒子,此时若小盒子已满,也直接输出,这里的检查是序号单调递增的,N个检查完之后进入(2)环节,即没有小松针在推送器上了
(2)推送器上没有小松针:此时检查小盒子内是否有小松针,若有,则按要求不超过K个且满足松针大小单调非递增性质依次pop,直至empty

#include<bits/stdc++.h>
using namespace std;
int a[1005];
int b[1005];
int cnt = 1;
stack<int> s;
int main(){
    
    
	int N,M,K;
	scanf("%d%d%d",&N,&M,&K);
	for(int i=1;i<=N;i++){
    
    
		scanf("%d",&a[i]);
	}
	while(cnt<=N){
    
    
		int count = 0;
		int Height = 999;
		while(!s.empty() && count < K){
    
    
			if(s.top()<=Height){
    
    
				Height = s.top();
				b[++count] = s.top();
				s.pop();
			}else{
    
    
				break;
			}
		}
		if(count == K){
    
    
			for(int i=1;i<=count;i++){
    
    
				if(i == 1){
    
    
					printf("%d",b[i]);
				}else{
    
    
					printf(" %d",b[i]);
				}
			}
			printf("\n");
		}else{
    
    
			while(cnt<=N && count<K){
    
    
				if(a[cnt]<=Height){
    
    
					b[++count] = a[cnt];
					Height = a[cnt];
					cnt++;
				}else{
    
    
					int size = s.size();
					if(size<M){
    
    
						s.push(a[cnt]);
						cnt++;
					}else{
    
    
						break;
					}
				}
			}
			for(int i=1;i<=count;i++){
    
    
				if(i == 1){
    
    
					printf("%d",b[i]);
				}else{
    
    
					printf(" %d",b[i]);
				}
			}
			printf("\n");
		}
	}
	while(!s.empty()){
    
    
		int count = 0;
		int Height = 999; 
		while(!s.empty() && count<K && s.top()<=Height){
    
    
			b[++count] = s.top();
			Height = s.top();
			s.pop();
		}
		for(int i=1;i<=count;i++){
    
    
			if(i == 1){
    
    
				printf("%d",b[i]);
			}else{
    
    
				printf(" %d",b[i]);
			}
		}
		printf("\n");		
	}
	return 0;
} 

L2-042 老板的作息表(25分)

算法标签: 排序

#include<bits/stdc++.h>
using namespace std;
struct node{
    
    
	int start;
	int end;
};
const int maxn = 1e5+5;
node t[maxn];
bool cmp(node t1,node t2){
    
    
	if(t1.start!=t2.start){
    
    
		return t1.start < t2.start;
	}else{
    
    
		return t1.end < t2.end;
	}
}
int time_to_int(int h,int m,int s){
    
    
	return 3600*h + 60*m + s;
}
void int_to_time(int t1,int t2){
    
    
	int h1 = t1/3600;
	int m1 = t1%3600/60;
	int s1 = t1%60;
	int h2 = t2/3600;
	int m2 = t2%3600/60;
	int s2 = t2%60;
	printf("%02d:%02d:%02d - %02d:%02d:%02d\n",h1,m1,s1,h2,m2,s2);
}
int main(){
    
    
	int N;
	scanf("%d",&N);
	for(int i=1;i<=N;i++){
    
    
		int h1,h2,m1,m2,s1,s2;
		scanf("%d:%d:%d - %d:%d:%d",&h1,&m1,&s1,&h2,&m2,&s2);
		t[i].start = time_to_int(h1,m1,s1);
		t[i].end = time_to_int(h2,m2,s2);
	}
	sort(t+1,t+1+N,cmp);
	int begin = 0;
	for(int i=1;i<=N;i++){
    
    
		if(t[i].start>begin){
    
    
			int_to_time(begin,t[i].start);
			begin = t[i].end;
		}else{
    
    
			begin = t[i].end;
		}
	}
	if(begin!=86399){
    
    
		int_to_time(begin,86399);
	}
	return 0;
}

L2-043 龙龙送外卖(25分)

L2-044 大众情人(25分)

算法标签: 图论 + Floyd
注意点: Floyd模板题,算法细节具体可详见数据结构专题系列——最短路
本题需仔细理解这句话:我们记一个人 i i i在一个异性 j j j眼中的距离感为 D i j ; D_{ ij}; Dij; i i i的“异性缘”定义为 1 m a x j ∈ S ( i ) ( D i j ​ ) \frac{1}{max_{j∈S(i)}{(D_{ij}​ )}} maxjS(i)(Dij)1,其中 S ( i ) S(i) S(i)是相对于 i i i的所有异性的集合。那么“大众情人”就是异性缘最好(值最大)的那个人。
要使得值最大,那么就是求 m a x ( D i j ) max(D_{ij}) max(Dij)最小的那组结果;
相对于 i i i的所有异性的集合,这意味着我们比较的是j眼中的i尽可能小,用数据结构语言描述为dp[j][i]最小(注意不是dp[i][j]

#include<bits/stdc++.h>
using namespace std;
int hashT[505];
int dp[505][505];
int res[505];

int main(){
    
    
	int N,M;
	scanf("%d%d",&N,&M);
	memset(dp,0x3f,sizeof(dp));
	for(int i=1;i<=N;i++){
    
    
		dp[i][i] = 0;
	}
	for(int i=1;i<=N;i++){
    
    
		char sex;
		cin >> sex;
		if(sex == 'F'){
    
    
			hashT[i] = 2;
		}else{
    
    
			hashT[i] = 1;
		}
		int K;
		scanf("%d",&K);
		for(int j=1;j<=K;j++){
    
    
			int num,dis;
			scanf("%d:%d",&num,&dis);
			dp[i][num] = min(dp[i][num],dis);
		}
	}
	for(int k=1;k<=N;k++){
    
    
		for(int i=1;i<=N;i++){
    
    
			for(int j=1;j<=N;j++){
    
    
				dp[i][j] = min(dp[i][j],dp[i][k]+dp[k][j]);	
			}
		}	
	}
	int maxm = INT_MAX;
	for(int i=1;i<=N;i++){
    
    
		if(hashT[i] == 2){
    
    
			int maxt = -1;
			for(int j=1;j<=N;j++){
    
    
				if(hashT[j] == 1){
    
    
					maxt = max(maxt,dp[j][i]);
				}
			}
			maxm = min(maxm,maxt);
		}
	}
	int cnt = 0;
	for(int i=1;i<=N;i++){
    
    
		if(hashT[i] == 2){
    
    
			int maxt = -1;
			for(int j=1;j<=N;j++){
    
    
				if(hashT[j] == 1){
    
    
					maxt = max(maxt,dp[j][i]); 
				}
			}
			if(maxt == maxm){
    
    
				if(!cnt){
    
    
					printf("%d",i);
				}else{
    
    
					printf(" %d",i);
				}
				cnt++;
			}
		} 
	}
	printf("\n");
	maxm = INT_MAX;
	cnt = 0;
	for(int i=1;i<=N;i++){
    
    
		if(hashT[i] == 1){
    
    
			int maxt = -1;
			for(int j=1;j<=N;j++){
    
    
				if(hashT[j] == 2){
    
    
					maxt = max(maxt,dp[j][i]);
				}
			}
			maxm = min(maxm,maxt);
		}
	}
	for(int i=1;i<=N;i++){
    
    
		if(hashT[i] == 1){
    
    
			int maxt = -1;
			for(int j=1;j<=N;j++){
    
    
				if(hashT[j] == 2){
    
    
					maxt = max(maxt,dp[j][i]); 
				}
			}
			if(maxt == maxm){
    
    
				if(!cnt){
    
    
					printf("%d",i);
				}else{
    
    
					printf(" %d",i);
				}
				cnt++;
			}
		} 
	}
	printf("\n");
	return 0;
}

Guess you like

Origin blog.csdn.net/weixin_41801682/article/details/123994945