PAT (Advanced Level) Practice

 

 

 

1001:A+B Format (20 分)(AC:stack)

注意要点:

1.注意0的时候的问题。

#include<iostream>
#include<stack>
using namespace std;

stack<char> s;

int main(){
	int a , b , count = 0 , n = 0;
	scanf("%d %d" , &a , &b);
	int t = a + b;
	//全是对于t的正数操作// 
	if(t < 0){
		t = -t;
	}
	//对于 t 的处理// 
	while(t != 0){
		char c = t % 10 + '0';
		s.push(c);
		count ++;
		if(count  == 3){
			s.push(',');
			count =0;
		}
		t /= 10;
	}
	//判断正负//
	if(a + b < 0){
		printf("-");
	} 
	if(a + b == 0){
		printf("0");
		return 0;
	}
	//输出//
	while(!s.empty()){
		if(n == 0 && s.top() == ','){
			s.pop();
			n ++;
			continue;
		}
		printf("%c" , s.top());
		s.pop();
		n ++;
	} 
	return 0;
}

 

1002:A+B for Polynomials (25)(AC)

注意要点:

1.float数组类型初始化的时候切记内部数字也得是0.0,要不然真的死都不知道怎么死的。

2.多组数据只要是后面不用的,都可以共用一个。

#include<iostream>
using namespace std;
int main() {
	int M;
	int a; 
	float b;
	int num = 0;
	float p[1005] = {0.0} ; //注意这个地方//
	scanf("%d" , &M);
	//第一行// 
	for(int i = 0 ; i < M ; i ++) {
		scanf("%d %f" , &a , &b);
		p[a] += b ;
	}
	//第二行// 
	getchar();
	scanf("%d" , &M);//可以直接覆盖// 
	for(int i = 0 ; i < M ; i ++) {
		scanf("%d %f" , &a , &b);
		p[a] += b; //在第一行基础之上往上加// 
	}
	//统计个数// 
	for(int i = 0 ; i < 1005 ; i ++){
		if(p[i] != 0) num ++;
	}
	printf("%d" , num);
	for(int i = 10 ; i >= 0 ; i --){
		if(p[i] != 0) 
			printf(" %d %.1f" , i , p[i]); 
		
	}
	return 0;
} 

 

1003:Emergency (25 分)(AC)

注意要点:

1.Dijkstra + BFS

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAXV = 505;
const int INF = 1000000;

int G[MAXV][MAXV] , num[MAXV] , w[MAXV] , d[MAXV] , weight[MAXV];
int N , M , S , D; 
bool vis[MAXV] = { 0 };

void Dijkstra(int S){
	//初始化//
	fill(d , d + MAXV , INF);
	memset(w , 0 , sizeof(w));
	memset(num , 0 , sizeof(num));
	//开始各种标记//
	d[S] = 0;
	w[S] = weight[S];
	num[S] = 1;
	//遍历每个点//
	for(int i = 0 ; i < N ; i ++) {
	//找到d之中最小的//
		int u = -1 , MIN = INF;
		for(int j = 0 ; j < N ; j ++){
			if(vis[j] == false && d[j] < MIN){
				u = j;
				MIN = d[j];
			}
		}
	//特殊情况找不到,退出//
		if(u == -1) return ;
		vis[u] = true;
	//修改值// 
		for(int v = 0 ; v < N ; v ++) {
			if(vis[v] == false && G[u][v] != INF){
				if(d[u] + G[u][v] < d[v]){
					d[v] = d[u] + G[u][v];
					w[v] = w[u] + weight[v];
					num[v] = num[u];
				}
				else if(d[u] + G[u][v] == d[v]){
						if(w[u] + weight[v] > w[v])
							w[v] = w[u] + weight[v];
						num[v] += num[u];
				}
			}
		}
	}
}

int main() {
	int a , b , c;
	scanf("%d %d %d %d" , &N , &M , &S , &D);
	for(int i = 0 ; i < N ; i ++) {
		scanf("%d" , &weight[i]);//救援队既是权值//		 
	}
	
	fill(G[0] , G[0] + MAXV * MAXV , INF);
	
 	for(int i = 0 ; i < M ; i ++) {
		scanf("%d %d %d" , &a , &b , &c);
		G[a][b] = c;
		G[b][a] = c;
	}
	Dijkstra(S);
	printf("%d %d\n" , num[D] , w[D]);
	return 0;
}

 

1004:Counting Leaves (30 分)(AC:DFS)

注意要点:

1.一开始的思路是去建立一棵树,想了想发现DFS也可以做出来。

2.强化DFS问题解决方式:递归 + 边界判断。 

#include<iostream>
#include<vector>
using namespace std;
const int MAXN = 105;

vector<int> v[MAXN];
int J[MAXN];
int D = -1;

void DFS(int x , int depth){
    //边界// 
	if(v[x].size() == 0){
    	J[depth] ++;
    	D = max(depth , D);
    	return ;
	}
	//递归//
	for(int i = 0 ; i < v[x].size() ; i ++){
		DFS(v[x][i] , depth + 1);
	} 
}

int main(){
	int N , M , ID , K , a;
	//输入// 
	scanf("%d %d" , &N , &M);
	for(int i = 0 ; i < M ; i ++){
		scanf("%d %d" , &ID , &K);
		for(int j = 0 ; j < K ; j ++){
			scanf("%d" , &a);
			v[ID].push_back(a);
		}
	}
	//DFS//
	DFS(1 , 0);
	//输出// 
	for(int i = 0 ; i <= D ; i ++){
		if(i == 0){
			printf("%d" , J[i]);
		}
		else{
			printf(" %d" , J[i]);
		}
	}
	return 0;
}

 

1005:Spell It Right (20 分)(AC:Vector)

注意要点:

1.0的情况考虑一下。

#include<iostream>
#include<vector>
using namespace std;

vector<int> v;

int main(){
	int sum = 0 ;
	char a;
	char b[10][10] = {"zero" , "one" , "two" , "three" , "four" , "five" , "six" , "seven" , "eight" , "nine"};
	//输入// 
	while(scanf("%c" , &a) == 1){
		if(a != '\n')
			sum =sum + (a - '0');
	}
	//倒着插入//
	if(sum == 0){
		printf("zero");
	} 
	else{
		while(sum != 0){
			int c =  sum % 10;
			v.push_back(c);
			sum /= 10;	
		}
		//输出//
		for(int i = v.size() - 1 ; i >= 0 ; i --){
			if(i == v.size() - 1){
				printf("%s" , b[v[i]]);
			}
			else{
				printf(" %s" , b[v[i]]);
			}
		}
	}
	return 0;
}

 

1007:Maximum Subsequence Sum (DP)

掌握了一个基本的dp问题的思路。

先写边界,随后确定递推公式。基本的模型一定要先理解清楚,随后做题才能在此基础之上进一步求解。

#include<iostream>
using namespace std;
const int MAXN = 10005;

int main(){
	int K;
	int a[MAXN] , dp[MAXN];//dp的含义是指,在这个数值状态下的最大的数值是多少// 
	int s[MAXN] = { 0 };
	bool flag = true;
		
	scanf("%d" , &K);
	for(int i = 0 ; i < K ; i ++){
		scanf("%d" , &a[i]);
		if(a[i] >= 0){
			flag = false;
		}
	}
	if(flag == true){//如果有一个数字是负数的话,则直接输出// 
		printf("%d %d %d" , 0 , a[0] , a[K - 1]);
		return 0;
	}
	dp[0] = a[0];//第一个数值就是其本身//
	for(int i = 1 ; i < K ; i ++){
		if(dp[i - 1] + a[i] > a[i]){ // 
			dp[i] = dp[i - 1] + a[i]; 
			s[i] = s[i - 1];
		}
		else{
			dp[i] = a[i];
			s[i] = i; 
		}		
	} 
	int n = 0;
	for(int i = 1 ; i < K ; i ++){
		if(dp[i] > dp[n]){
			n = i;
		}
	} 
	printf("%d %d %d\n" , dp[n] , a[s[n]] , a[n]);
	return 0;
}

 

1008:Elevator (20 分)(AC:vector数学问题)

注意要点:

无。

#include<iostream>
#include<vector>
using namespace std;

vector<int> v;

int main(){
	int N , a , d = 0;
	//输入// 
	scanf("%d" , &N);
	for(int i = 0 ; i < N ; i ++){
		scanf("%d" , &a);
		v.push_back(a);
	}
	//层数操作//
	for(int i = 0 ; i < v.size() ; i ++){
		//一层// 
		if(i == 0){
			d = d + (v[i] - 0) * 6 + 5;
		}
		//二层以上 , 比你高// 
		else if( i != 0 && (v[i] > v[i - 1])){
			d = d + ((v[i] - v[i - 1]) * 6 + 5);
		}
		// 二层以上,比你低//
		else{
			d = d + ((v[i - 1] - v[i]) * 4 + 5);
		} 
	} 
	printf("%d" , d);
	return 0;
}

 

1009:Product of Polynomials (25 分)(AC:数学模拟)

注意要点:

1.审题,注意这个题目是要求乘法,我一开始做成加法了, 浪费了很多时间。

2.double类型只能由lf来接,否则都是根本接不到。

3.这个题思路也是很清晰,几乎不用拐弯,我开了两个数组的原因是不想交叉起来不好修改。

#include<iostream>
using namespace std;
int main(){
	int N , M , a , c , maxn = -1 , count = 0;
	double b , d;
	double A[10000] = { 0 } , B[10000] = { 0 };
	//输入// 
	scanf("%d" , &N);
	for(int i = 0 ; i < N ; i ++){
		scanf("%d %lf" , &a , &b);
		A[a] = A[a] + b;
		//边界//
		if(a > maxn){
			maxn = a; 
		}	
	}
	scanf("%d" , &M);
	for(int j = 0 ; j < M ; j ++){
		scanf("%d %lf" , &c , &d);
		//换到B数组里面// 
		for(int i = maxn ; i >= 0 ; i --){
			if(A[i] != 0){
				B[i + c] = B[i + c] + d * A[i];
				if(i + c > maxn){
					maxn = i + c;
				} 
			}	
		}	
	}
	for(int i = 0 ; i <= maxn ; i ++){
		if(B[i] != 0){
			count ++;
		}
	}
	//输出//
	printf("%d " , count);
	for(int i = maxn ; i >= 0 ; i --){
		if(B[i] != 0.0){
			printf("%d %.1lf" , i , B[i]);
			count --;
			if(count > 0)
				printf(" ");
		}
	} 
	return 0;
}

 

1011:World Cup Betting (20 分)(AC:数学模拟)

注意要点:

1.这个输出着实牛啤,还能这么输出。

#include<iostream>
using namespace std;

int main(){
	float a, sum = 1 ;
	int k;
	char S[3] = {'W' , 'T' , 'L'};//对应字符表// 
	//输入// 
	for(int i = 0 ; i < 3 ; i ++){
		float max = -1.0 ;
		for(int j = 0 ; j < 3 ; j ++){
			scanf("%f" , &a);
			if(a > max){
				max = a;
				k = j;
			}
		}
		printf("%c " , S[k]);
		sum *= max;
	}
	//输出2//
	printf("%.2f" , (sum * 0.65 - 1) * 2); 
	return 0;
}

 

1013:Battle Over Cities (25 分)(AC :DFS , 并查集)

注意要点:

1.dfs之后改用连接表,不要使用图了。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int INF = 10000000;

vector<int> v[1005];
int c;
bool vis[1005];
void dfs(int e){
	if(e == c) return ;
	vis[e] = true;
	for(int i = 0 ; i < v[e].size() ; i ++){
		if(vis[v[e][i]]== false){
			dfs(v[e][i]);
		}
	}
}

int main(){
	int N , M , K ,a , b;
	//输入// 
	scanf("%d %d %d" , &N , &M , &K);
	for(int i = 0 ; i < M ; i ++){
		scanf("%d %d" , &a , &b);
		v[a].push_back(b);
		v[b].push_back(a);
	}
	//输出//
	for(int i = 0 ; i < K ; i ++){
		scanf("%d" , &c);
		memset(vis , false , sizeof(vis));
		int block = 0;
		for(int i = 1 ; i <= N ; i ++){
			if(i != c && vis[i] == false){
				dfs(i);
				block ++;
			}
		}
		printf("%d\n" , block - 1);	
	} 
	return 0;
}

 

1020:Tree Traversals (25 分)(AC)

注意要点:

2.这个层序遍历的这个地方非常容易错,修改了两三次才AC了。

#include<iostream>
#include<queue>
using namespace std;
struct node{
	int data;
	node* lchild;
	node* rchild;
};

int pos[55] , in[55];
int N; 
//利用后根数列和中根数列求原来的数列// 
node* creat(int posL , int posR , int inL , int inR) {
	//边界// 
	if(posL > posR){
		return NULL;
	}
	//求根节点// 
	node* root = new node;
	root->data = pos[posR];
	int k;
	for(k = inL ; k <= inR ; k ++) {
		if(in[k] == pos[posR])
			break;
	}
	//左右分支// 
	int numleft = k - inL;
	root->lchild = creat(posL , posL + numleft - 1 , inL , k - 1);//易错//
	root->rchild = creat(posL + numleft , posR - 1, k + 1 , inR);
	return root;
}

//利用BFS来输出这个层序遍历。// 
int num = 0 ; 
void BFS(node* root) {
	queue<node*> q;
	q.push(root);
	while(!q.empty()){
		node* t = q.front();
		q.pop();
		printf("%d" , t->data);
		num ++;
		if(num < N) printf(" ");
		if(t->lchild != NULL)	q.push(t->lchild);
		if(t->rchild != NULL)	q.push(t->rchild);
	}
}

int main() {
	scanf("%d" , &N);
	for(int i = 0 ; i < N ; i ++) {
		scanf("%d" , &pos[i]);
	}
	for(int i = 0 ; i < N ; i ++) {
		scanf("%d" , &in[i]); 
	}
	node* root = creat(0 , N - 1 , 0 , N - 1);
	BFS(root);
	return 0;	 
}

 

1030:Travel Plan (30 分)(AC:Dijkstra第二形态 + 记忆化DFS)

注意要点:

1.这个地方注意这是个无向图。需要注意来回的数值都可以。

2.巧了,不知道为什么PTA的数值题目都可以用 Matrix 来做。看来数据还是小。

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int MAXN = 505;
const int INF = 100005;

//初始化定义// 
int G[MAXN][MAXN];
int cost[MAXN][MAXN]; 
int d[MAXN] , x[MAXN];
int pre[MAXN];
bool vis[MAXN];
int N , M , S , D;
int a , b , c , de;

void Dijkstra(int s){
	fill(d , d + MAXN , INF);
	fill(x , x + MAXN , INF);
	//Ñ°ÕÒÇ°Çý½áµã// 
	for(int i = 0 ; i < N ; i ++){
		pre[i] = i;
	}
	d[s] = 0;
	x[s] = 0;
	for(int i = 0 ; i < N ; i ++){
		int u = -1 , MIN = INF;
		//第一步:找最小值// 
		for(int j = 0 ; j < N ; j ++){
			if(vis[j] == false && d[j] < MIN){
				MIN = d[j];
				u = j;
			}
		}
		//第二步:确定范围//
		if(u == -1) return ;
		//第三步:更新数值//
		vis[u] = true; 
		for(int v = 0 ; v < N ; v ++){
			if(vis[v] == false && G[u][v] != INF){
				if(d[u] + G[u][v] < d[v]){
					d[v] = d[u] + G[u][v];
					x[v] = x[u] + cost[u][v];
					pre[v] = u;
				}
				else if(d[u] + G[u][v] == d[v]){
					if(x[u] + cost[u][v] < x[v]){
						x[v] = x[u] + cost[u][v];
						pre[v] = u;
					}
				}
			}
		}
	}
}

//记忆化搜索// 
void DFS(int v){
	if(v == S){
		printf("%d " , S);
		return ;
	}
	DFS(pre[v]);
	printf("%d " , v);
}

int main(){
	//初始化数据// 
	fill(d , d + MAXN , false);
	fill(G[0] , G[0] + MAXN * MAXN , INF);
	//ÊäÈë// 
	scanf("%d %d %d %d" , &N , &M , &S , &D);
	for(int i = 0 ; i < M ; i ++){
		scanf("%d %d %d %d" , &a , &b , &c , &de);
		G[a][b] = c;
		G[b][a] = c;
		cost[a][b] = de;
		cost[b][a] = de;
	}
	//最短路径//
	Dijkstra(S);
	//输出//
	DFS(D);
	printf("%d %d\n" , d[D] , x[D]); 
}

 

1031:Hello World for U (20 分)(AC:打印图案)

思路提示:

1.首先需要确定n1 , n2 , n3的数值,其次按照边框再每一个打印出来,最后二维数组写出。

注意要点:

1.最后强调一次这个memset这个功能。在cstring头文件下。

#include<iostream>
#include<cstring>
using namespace std;
int main(){
	char s[100];
	char m[100][100];
	memset(m , ' ' , sizeof(m)); 
	scanf("%s" , s);
	//确定n1 , n2 , n3 //
	int len = strlen(s) + 2;
	int n1 = len / 3;
	int n3 = n1;
	int n2 = len / 3 + len % 3;
	//填入数组中//
	int k = 0 ;
	for(int i = 0; i < n1 ; i ++){//n1// 
		m[i][0] = s[k ++];
	} 
	for(int i = 1 ; i <= n2 - 2 ; i ++){//n2// 
		m[n1 - 1][i] = s[k ++];
	}
	for(int i = n3 - 1 ; i >= 0 ; i --){//n3// 
		m[i][n2 - 1] = s[k ++];
	}
	//输出// 
	for(int i = 0 ; i < n1 ; i ++){
		for(int j = 0 ; j < n2 ; j ++){
			printf("%c" , m[i][j]);
		}
		printf("\n");
	}
	return 0;
}

 

1033:Sharing (25 分)(AC:模拟链表)

思路提示:

1.模拟链表的技巧。

注意要点:

%05d,超容易犯错。

#include<iostream>
const int MAXN = 100005;
using namespace std;
struct node{
	char data;
	int next;
}Node[MAXN];
int main(){
	int s1 , s2 , n , a , c , k = 0;
	char b;
	bool L[MAXN] = { false };
	//输入// 
	scanf("%d %d %d" , &s1 , &s2 , &n);
	for(int i = 0 ; i < n ; i ++){
		scanf("%d %c %d" , &a , &b , &c);
		Node[a].data = b;
		Node[a].next = c;
	}
	//第一轮//
	int root = s1; 
	while(root != -1){
		L[root] = true;
		root = Node[root].next;	
	}
	L[root] = true;
	
	//第二轮:找交点//
	int root2 = s2;
	while(root2 != -1){
		if(L[root2] == true){
			printf("%05d" , root2);
			L[root2] = false;//防止下次判断//	
			break;
		}
		root2 = Node[root2].next;	
	}
	if(L[root2] == true)
		printf("-1");		
	return 0;
}

 

1035:Password (20 分)(AC::水题)

思路提示:请认真读题。

注意要点:

1.这个地方注意这个多数和单一的情况。

#include<iostream>
#include<cstring>
using namespace std;
struct A{
	string b;//第一个字符串//
	string c;//第二个字符串//
	bool flag;//判断这个是否修改过//
}a[1005];

int main(){
	int n , count = 0;
	scanf("%d" , &n);
	for(int i = 0 ; i < n ; i ++){
		cin >> a[i].b >> a[i].c;
		for(int j = 0 ; j < a[i].c.size() ; j ++){//不停的进行修改保存// 
			if(a[i].c[j] == '1'){
				a[i].c[j] = '@';
				a[i].flag = 1;
				continue;
			}
			if(a[i].c[j] == '0'){
				a[i].c[j] = '%';
				a[i].flag = 1;
				continue;
			}
			if(a[i].c[j] == 'l'){
				a[i].c[j] = 'L';
				a[i].flag = 1;
				continue;
			}
			if(a[i].c[j] == 'O'){
				a[i].c[j] = 'o';
				a[i].flag = 1;
				continue;
			}
		} 
		if(a[i].flag == 1){
				count ++;//有问题个数的统计// 
		}
	}
	//输出// 
	if(n == 1 && count == 0){//1的情况// 
		printf("There is 1 account and no account is modified");
	} 
	else if(count == 0){//多数的情况// 
		printf("There are %d accounts and no account is modified" , n);
	}
	else{//输出错误的情况// 
		printf("%d\n" , count);
		for(int i = 0 ; i < n ; i ++){
			if(a[i].flag == 1){
				cout << a[i].b << " " << a[i].c;
				count --;
				if(count != 0){
					printf("\n");
				}
			}	
		}
	}
	return 0;
} 

 

1036:Boys vs Girls (25 分)(AC :水题)

注意要点:注意读题,缺的地方写Absent。

#include<iostream>
#include<cstring>
#include<math.h>
using namespace std;

int main(){
	int n , maxm = 10000 , maxn = -1 ;
	string maxmID , maxmname , maxnID , maxnname;
	scanf("%d" , &n);
	for(int i = 0 ; i < n ; i ++){
		int number;
		char sex ;
		string ID , name;
		cin >> name >> sex >> ID >> number;
		if(sex == 'M' && maxm > number){//成绩为男性// 
			maxmname = name;
			maxmID = ID;
			maxm = number;
		}
		if(sex == 'F' && maxn < number){//成绩为女性// 
			maxnname = name;
			maxnID = ID;
			maxn = number;
		}
	}
	//输出//
	if(maxm == 10000 || maxn == -1){//缺一个// 
		if(maxm == 10000)	
			cout << maxnname << " " << maxnID << endl << "Absent" << endl << "NA";
		if(maxn == -1)
			cout << "Absent" << endl << maxmname << " " << maxmID << endl << "NA";	
		
	}
	else{//全有// 
		cout << maxnname << " " << maxnID << endl;
		cout << maxmname << " " << maxmID << endl;
		printf("%d" , abs(maxn - maxm));	
	}
	return 0;
}

 

1040:Longest Symmetric String (25 分)(AC:DP)

注意要点:控制每次移动的长度,从1-3。

#include<iostream>
#include<cstring>
using namespace std;

int dp[1005][1005];

int main(){
	string s;//注意小写string// 
	int ans = 1;
	getline(cin , s);//专用空格// 
	int len = s.size();
	memset(dp , 0 , sizeof(dp));//长度为 1和 2 的情况// 
	for(int i = 0 ; i < len ; i ++){
		dp[i][i] = 1;
		if(i < len - 1){
			if(s[i] == s[i + 1]){
				dp[i][i + 1] = 1; 
				ans = 2;
			}
		}
	}
	//处理数据长度为3// 
	for(int L = 3 ; L <= len ; L ++){
		for(int i = 0 ; i + L - 1 < len ; i ++){
			int j = i + L - 1;//记录末尾值// 
			if(s[i] == s[j] && dp[i + 1][j - 1] == 1){
				dp[i][j] = 1;
				ans = L;
			}
		}
	}
	printf("%d" , ans);
	return 0;
} 

 

1043:Is It a Binary Search Tree (25 分)(AC)

注意要点:

这个题目非常好,典型的二叉搜索树的体现。操作类似于树的操作。

#include<iostream>
#include<vector>
using namespace std;

struct node{
	int data;
	node *left;
	node *right;
};

void insert(node* &root , int a) {
	if(root == NULL){
		root = new node;
		root->data = a;
		root->left = NULL;
		root->right = NULL;	
		return ;
	}
	if(a < root->data)	insert(root->left , a);
	else	insert(root->right , a);
}

void preorder(node* root , vector<int>&v){
	if(root == NULL){
		return ;
	}
	v.push_back(root->data);
	preorder(root->left , v);
	preorder(root->right , v);
}

void preorderM(node* root , vector<int>&v){
	if(root == NULL){
		return ;
	}
	v.push_back(root->data);
	preorderM(root->right , v);
	preorderM(root->left , v);
}

void postorder(node* root , vector<int>&v){
	if(root == NULL){
		return ;
	}
	postorder(root->left , v);
	postorder(root->right , v);
	v.push_back(root->data);
}

void postorderM(node* root , vector<int>&v){
	if(root == NULL){
		return ;
	}
	postorderM(root->right , v);
	postorderM(root->left , v);
	v.push_back(root->data);
}

vector<int>origin , pre , preM , post , postM;//初始, 前序 , 后序 , 平衡前序 , 平衡后序//  
int main() {
	int N , a;
	node *root = NULL;
	//输入// 
	scanf("%d" , &N);
	for(int i = 0 ; i < N ; i ++) {
		scanf("%d" , &a);
		origin.push_back(a);
		insert(root , a); 
	}
	//前序//
	preorder(root , pre);
	//镜像前序//
	preorderM(root , preM);
	//后序//
	postorder(root , post); 
	//镜像后序//
	postorderM(root , postM);
	if(origin == pre){
		printf("YES\n");
		for(int i = 0 ;  i < post.size() ; i ++) {
			if(i == post.size() - 1) 
				printf("%d" , post[i]);
			else	
				printf("%d " , post[i]);
		}
	} 
	else if(origin == preM){
			printf("YES\n");
			for(int i = 0 ;  i < postM.size() ; i ++) {
				if(i == postM.size() - 1) 
					printf("%d" , postM[i]);
				else	
					printf("%d " , postM[i]);
			}
	}
	else{
		printf("NO\n");
	}
	return 0;
} 


 

1045:Favorite Color Stripe(LCS)

这个题目其实LIS也是可以做的,但是我没有做。以后有时间补上。

一开始我还在想这个地方会不会有冲突出现,但是一想,LCS已经完美的解决了这个问题,关键是这个地方他有个重复的问题在里面。当前的状态如果没有匹配到的话,那就直接把前面的数值补进来。

#include<iostream>
using namespace std;
const int MAXM = 205;
const int MAXL = 10005;

int a[MAXM] , b[MAXL] , dp[MAXM][MAXL];//这个要定义到外面,内部空间不够会报错.dp表示当前的最大的数值// 

int main(){
	int n , m , l;
	scanf("%d" , &n);
	scanf("%d" , &m);
	for(int i = 1 ; i <= m ; i ++){
		scanf("%d" , &a[i]);
	}
	scanf("%d" , &l);
	for(int i = 1 ; i <= l ; i ++){
		scanf("%d" , &b[i]);
	}
	//边界//
	for(int i = 0 ; i <= m ; i ++){
		dp[i][0] = 0;
	} 
	for(int i = 0 ; i <= l ; i ++){
		dp[0][i] = 0;
	}
	//递推// 
	for(int i = 1 ; i <= m ; i ++){
		for(int j = 1 ; j <= l ; j ++){
			if(a[i] == b[j]){
				dp[i][j] = max(dp[i - 1][j] , dp[i][j - 1]) + 1;
			}
			else{
				dp[i][j] = max(dp[i - 1][j] , dp[i][j - 1]);
			}
		}
	}
	printf("%d\n" , dp[m][l]);
	return 0;
}

 

1047:Student List for Course(25 分)(AC)

注意要点:

1.这个地方因为不需要输入名字,所以不用hash了。

2.注意字典序的用法。

3.这个地方C的写法。二维数组换成了几个一维数组字符串。

#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
char C[40005][5];
vector<int> course[40005];

bool cmp(int a , int b) {
	return strcmp(C[a] , C[b]) < 0 ;//这个地方注意字典序的排列//
}

int main(){
	int N , K;
	int c , d;
	scanf("%d %d" , &N , &K);
	for(int i = 0 ; i < N ; i ++) {
		scanf("%s %d" , C[i] , &c);
		for(int j = 0 ; j < c ; j ++) {
			scanf("%d" , &d);
			course[d].push_back(i);
		}
	}
	//输出//
	for(int i = 1 ; i <= K ; i ++) {
		printf("%d %d\n" , i , course[i].size());
		sort(course[i].begin() , course[i].end() , cmp);
		for(int j = 0 ; j < course[i].size() ; j ++) {
				printf("%s\n" , C[course[i][j]]);
		}
	}
	
	return 0;	
}

 

1053:Path of Equal Weight (30 分)(AC)

注意要点:

1.一开始这个路径这个地方需要设置开头的点为0。

2.注意每次实现完之后都要return (因为 return 的是上一级)。

3.这个地方记录一下这个path的问题。其实path本身并不是完全记录每一条的路径。他其实就是一个再覆盖。
本身的地方在于这个输出。这个输出如果对了,就打印在他前面的所有节点的数据就可以了,而他后面的数据则不用管。 

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

int N , M , S , path[105];
struct node{
	int weight;
	vector<int> child;
}Node[105];

bool cmp(int a , int b){
	return Node[a].weight > Node[b].weight;
}
 
void DFS(int index , int num , int sum){
	if(sum > S) return ;//超了// 
	else if(sum == S){//正好// 
		if(Node[index].child.size()!= 0)
			return ;
		for(int i = 0 ; i < num ; i ++){
			if(i == num - 1)
				printf("%d\n" , Node[path[i]].weight);
			else
				printf("%d " , Node[path[i]].weight);
		}
	}
	else{//不够// 
		for(int i = 0 ; i < Node[index].child.size() ; i ++){
			int c= Node[index].child[i];
			path[num] = c;//这个地方其实是直接覆盖的。 
			DFS(c , num + 1 , sum + Node[c].weight);	
		}
	}
}

int main(){
	scanf("%d %d %d" , &N , &M , &S);
	for(int i = 0 ; i < N ; i ++){
		scanf("%d" , &Node[i].weight);
	}
	for(int i = 0 ; i < M ; i ++){
		int id , num , a;
		scanf("%d %d" , &id , &num);
		for(int j = 0 ; j < num ; j ++){
			scanf("%d" , &a);
			Node[id].child.push_back(a);
		}
		sort(Node[id].child.begin() , Node[id].child.end() , cmp);
	}
	path[0] = 0;//把id放进来// 
	DFS(0 , 1 , Node[0].weight);//起始点的位置数码 , 当前的元素的个数,当前元素的和// 
	return 0;
}

 

1063:Set Similarity(25 分)(AC)

注意要点:

1.注意输入的时候会出点问题,尽可能的分开输入的格式。

#include<iostream>
#include<set>
using namespace std;

set<int> a[55];

void fun(int b , int c) {
	int samenum = 0 , allnum = a[c].size();
	for(set<int>::iterator it = a[b].begin() ; it != a[b].end() ; it ++) {
		if(a[c].find(*it) != a[c].end())	samenum ++;
		else	allnum ++;
	} 
	printf("%.1f%%\n" , samenum * 100.0 / allnum);
}

int main() {
	int N , n , v;
	int c , b;
	int e ;
	scanf("%d" , &N);
	for(int i = 1 ; i <= N ; i ++) {
		scanf("%d" , &n);
		for(int j = 0 ; j < n ; j ++) {
			scanf("%d" , &v);
			a[i].insert(v);
		}
	}
	//输入// 
	scanf("%d" , &e);
	for(int i = 0 ; i < e ; i ++) {
		scanf("%d %d" , &b , &c);
		fun(b , c);
	}
	return 0;
}

 

1065:A+B and C (64bit) (20)(AC)

注意要点:

1。注意 long long 的写法,范围是(2 ^ - 63 , 2 ^ 63),这个一但求和值必然会超出 long long ,只需要考虑溢出的情况即可。

2。关于溢出,这个东西就是个环形的问题 ,数字超过范围符号变化到但是数字照样加,所以会出现负数的情况。所以你也可以理解,一旦两个正数加成负数必然是溢出,到那时你c的数值必不可能会超过 long long 。与此相反,另外一面情况也可以理解了。

#include<iostream>
using namespace std;
int main() {
	int N;
	int numcase = 1;
	scanf("%d" , &N);
	for(int i = 0 ; i < N ; i ++) {
		long long a , b , c;
		scanf("%lld%lld%lld", &a , &b , &c);
		long long r = a + b;
		bool flag ;
		//溢出情况检查// 
		if(a > 0 && b > 0 && c < 0) flag = true;
		else if(a < 0 && b < 0 && c >= 0) flag = false;
		//正常情况检查// 
		else if(r > c) flag = true;
		else flag = false;
		//输出// 
		if(flag == true) {
			printf("Case #%d: true\n" , numcase ++);
		}
		else {
			printf("Case #%d: false\n" , numcase ++);
		}
	}
	return 0;
} 

 

1068:Find More Coins(01背包 + 记忆化搜索)

注意要点:注意01背包的含义,前i个硬币恰好有v元可以买到东西。

其次是记忆化搜索。每个状态的时候就会更新这个状态下的硬币的情况,用flag来确定每个硬币的使用情况。

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAXN = 10005;
const int MAXM = 105;
int v[MAXN] , dp[MAXM];//dp的意思是指在前i个硬币恰好有v元能获得的价值// 
bool flag[MAXN] , choice[MAXN][MAXM];
//在这个地方的价格和体积是一样的,所以二者合并起来了// 
bool cmp(int a , int b){//因为这个题目是一个01背包,倒着输出// 
	return a > b; 
}

int main(){
	memset(dp , 0 , sizeof(dp));
	int N , M;
	scanf("%d %d" , &N , &M);
	for(int i = 1 ; i <= N ; i ++){
		scanf("%d" , &v[i]);
	}
	sort(v + 1 , v + N + 1 , cmp);//从1开始的sort的写法//
	//状态转移方程// 
	for(int i = 1 ; i <= N ; i ++){
		for(int V = M ; V >= v[i] ; V --){//这个地方的V已经代表了所有的情况了// 
			if(dp[V] <= dp[V - v[i]] + v[i]){ 
				dp[V] = dp[V - v[i]] + v[i];
				choice[i][V] = 1;//使用了一枚硬币// 
			}
			else choice[i][V] = 0;//没有使用一枚硬币// 
		}
	} 
	if(dp[M] != M){
		printf("No Solution");	
	}
	else{
		//记录整个路径//
		int k = N , num = 0 , c = M;
		while(k >= 0){
			
			if(choice[k][c] == 1){//如果说第k个状态下使用了// 
				flag[k] = true;//该种硬币标记为已经使用过了// 
				c = c - v[k];//价值减少// 
				num ++;
			}
			else{
				flag[k] = false;//没有就标记没有//  
			}
			k --;//往前翻//
		} 
		//输出//
		for(int i = N ; i >= 1 ; i --){
			
			if(flag[i] == true){
				printf("%d" , v[i]);
				num --;
				if(num > 0)	printf(" ");
			}
		} 
	}
	return 0;
}

 

1069:The Black Hole of Numbers(20 分)(AC)

注意要点:

1.sort的写法.

#include<iostream>
#include<algorithm>
using namespace std;

int a[5] = { 0 };

bool cmp(int a , int b) {
	return a > b ; 
}

void isarray(int N ) {
	for(int i = 0 ; i < 4 ; i ++) {
		a[i] = N % 10;
		N /= 10;
	}
}

int isnumber(int A[]) {
	int sum = 0;
	for(int i = 0 ; i < 4 ; i ++) {
		sum = sum * 10 + a[i];
	}
	return sum;
}

int main() {
	int N , min , max;
	scanf("%d" , &N);
	while(1) {
		isarray(N);
		sort(a , a + 4);
		min = isnumber(a);//最小值// 
		sort(a , a + 4 , cmp);
		max = isnumber(a); //最大值//
	    N = max - min ; 
	    printf("%04d - %04d = %04d\n" , max , min , N);
 		if(N == 0 || N == 6174) break; 
    }
    return 0;
}
 

 

1086:Tree Traversals Again (25 分)(AC)

注意要点:

1.模板题,就是一个模拟一个栈的输入和输出。

#include<iostream>
#include<stack>
#include<cstring>
using namespace std;
const int MAX = 50;

stack<int> s;
int N;
int pre[MAX] , in[MAX] , pos[MAX];
struct node{
	int data;
	node* lchild;
	node* rchild;
}; 

node* creat(int preL , int preR , int inL , int inR){
	//范围// 
	if(preL > preR)
		return NULL;
	//创建根节点// 
	node* root = new node;
	root->data = pre[preL];
	//在中序遍历中找到根节点// 
	int k;
	for(k = inL ; k <= inR ; k ++) {//千万注意这个地方如果前面定义了,则后面不能定义。// 
		if(pre[preL] == in[k]){
			break;
		}
	} 
	//切分寻找;注意技巧:左右的范围其实是对应可以接起来的。// 
	int numleft = k - inL ; 
	root->lchild = creat(preL + 1 , preL + numleft , inL , k - 1);
	root->rchild = creat(preL + numleft + 1 , preR , k + 1 , inR); 
	return root; 
}

int num = 0 ; 
void postorder(node* root) {
	if(root == NULL)
		return ;
	postorder(root->lchild);
	postorder(root->rchild);
	printf("%d" , root->data);
	num ++;
	if(num < N)
		printf(" ");
}

int main() {
	int a , preindex = 0 , inindex = 0;
	char opera[10];
	//输入操作// 
	scanf("%d" , &N);
	for(int i = 0 ; i < 2 * N ; i ++) {
		scanf("%s" , opera);
		if(strcmp(opera , "Push") == 0) {
			scanf("%d" , &a);
			pre[preindex ++] = a;
			s.push(a);
		}
		else {
			in[inindex ++] = s.top();
			s.pop();
		}
	}
	//建树, 这个地方注意是有几个根的数值就补几个。//
	node* root = creat(0 , N - 1, 0 , N - 1); 
	//后序遍历// 
	postorder(root);
	return 0;
} 

 

1101:Quick Sort(25 分)(AC)

注意要点:

1.思路很清晰,但是这个地方可以利用这个小技巧,因为你每次前面的数据就是这个这个最小值了,所以完全没有必要每次都去遍历前面的数据,直接可以与上一个数据进行比较就行。

2.本题目和QS完全没有任何关系,倒像是在给你介绍QS的原理。

2.这个地方注意有个坑,最后需要输出一个回车。我其实很费解这个东西。以后建议所有的题目之后都去写一个回车以防万一。

#include<iostream>
#include<algorithm>
using namespace std;
const int INF = 1000000000;
int main() {
	int N , sum = 0;
	int a[100005] = {0};
	int leftmax[100005] = {0};
	int rightmin[100005] = {0};
	
	//input// 
	scanf("%d" , &N);
	leftmax[0] = 0;
	rightmin[N - 1] = INF;
	for(int i = 0 ; i < N ; i ++) {
		scanf("%d" , &a[i]);
	}
	//leftmax:可修正,其实完全不必每次都把数据遍历一次//
	for(int i = 1 ; i < N ; i ++) {
		leftmax[i] = max(leftmax[i - 1] , a[i - 1]);
	}
	//rightmin,这个地方你想,如果要是N - 1 的话,N - 1 + 1 不就翻出数组外头去了。。//
	for(int i = N - 2; i >= 0 ; i --) {
		rightmin[i] = min(rightmin[i + 1] , a[i + 1]);
	}
	//statistic// 
	for(int i = 0 ; i < N ; i ++) {
		if(a[i] > leftmax[i] && a[i] < rightmin[i]) {
			sum ++;
		}
	}
	//output//
	printf("%d\n" , sum);
	for(int i = 0 ; i < N ; i ++) {
		if(a[i] > leftmax[i] && a[i] < rightmin[i]) {
	    	printf("%d" , a[i]);
	    	sum--;
	    	if(sum != 0) printf(" ");
		}
	}
	printf("\n");//无厘头的要求。// 
	return 0;
} 

 

1107:Social Clusters(30 分)(AC)

注意要点:

1/并查集。最难的不是并查集,而是主函数。

#include<iostream>
#include<algorithm>
using namespace std;

int father[1005] = {0} ; 
int isroot[1005] = {0} ;
int hobby[1005] = {0};

void init(int N) {
	for(int i = 1 ; i <= N ; i ++) {
		father[i] = i;
		isroot[i] = false;
	}
}

bool cmp(int a , int b) {
	return a > b ;
}

int findfather(int x) {
	int a = x;
	while(x != father[x]) {
		x = father[x];
	}
	while(a != father[a]){
		int z = a; 
		a = father[a];
		father[z] = x ;
	}
	return x;
}

void Union(int a , int b) {
	int A = findfather(a);
	int B = findfather(b);
	if(A != B) {
		father[A] = B ; 
	}
}

int main() {
	int N , k , d , sum = 0;
	scanf("%d" , &N);
	init(N);
	for(int i = 1 ; i <= N ; i ++){
		scanf("%d: " , &k);
		for(int j = 0 ; j < k ; j ++) {
			scanf("%d" , &d);
			if(hobby[d] == 0) {
				hobby[d] = i;
			}
			Union(i , findfather(hobby[d]));
		}
	}
	
	for(int i = 1 ; i <= N ; i ++) {
		isroot[findfather(i)] ++;
	}
	
	for(int i = 1 ; i <= N ; i ++) {
		if(isroot[i] != 0) {
			sum ++; 
		}
	}
	
	sort(isroot + 1 , isroot + N + 1 , cmp);
	
	printf("%d\n" , sum);
	for(int i = 1 ; i <= sum ; i++) {
			if(i == sum)
				printf("%d" , isroot[i]);
			else
				printf("%d " , isroot[i]);
	}
	return 0;
} 

1155. Heap Paths

解题思路:参考柳神。有的时候发现并不是不会做题,而是题目真的看不懂。。

1.利用dfs保存每条路径。(在dfs中打印数据)

2.判断大根堆和小根堆。(在大根堆中父亲节点的数据大于儿子节点的数据)


#include<iostream>
#include<vector>
using namespace std;

int n , a[1005];
vector<int> v;

void dfs(int x){
	if(2 * x > n && 2 * x + 1 > n){//×ó¸ù½ÚµãµÄÊýÖµ´óÓÚÕû¸öÊý¾Ý && ÓÒ¸ú½ÚµãµÄÊý¾Ý´óÓÚÕû¸öÊý¾Ý// 
		if(x <= n){//Õâ¸ö¸ùµÄ½ÚµãûÓгöÁ˽磬µ«ÊÇÕâ¸ö¸ùµÄ½Úµã³öÁ˽磬Ôò˵Ã÷Õâ¸öµØ·½µ½ÁËÄ©¶ËÁË// 
			for(int i = 0 ; i < v.size() ; i ++){//Õâ¸öµØ·½Ï൱ÓÚÊǶÔÓÚÕû¸ö·¾¶µÄÒ»¸ö±éÀú¡£ 
				printf("%d%s" , v[i] , i != v.size() - 1 ? " " : "\n");
			}
		}
	}
	else{
		v.push_back(a[2 * x + 1]);//ÏȽ«ÓÒ½Úµã·ÅÈ룬±éÀúÓÒ½ÚµãϵÄÊ÷// 
		dfs(2 * x + 1);
		v.pop_back();
		v.push_back(a[2 * x]);//ÔÙ½«×ó½Úµã·ÅÈ룬±éÀú×ó½ÚµãϵÄÊ÷// 
		dfs(2 * x);
		v.pop_back(); 
	}
}

int main(){
	bool ismin = false , ismax = false;
	scanf("%d" , &n);
	for(int i = 1 ; i <= n ; i ++){
		scanf("%d" , &a[i]);
	}
	v.push_back(a[1]);
	dfs(1);
	for(int i = 2 ; i <= n ; i ++){//Õâ¸öµØ·½´ÓµÚ¶þ¸ö½Úµã¿ªÊ¼,Èç¹û´ÓµÚÒ»¸ö½ÚµãÒ²¿ÉÒÔ// 
		if(a[i / 2] < a[i])	ismin = true;//Èç¹û×Ó½ÚµãµÄÊýÖµ±È¸ù½ÚµãµÄÊýֵҪСµÄ»°£¬ÊÇ´ó¸ù¶Ñ// 
		if(a[i / 2] > a[i])	ismax = true;//Èç¹û×Ó½ÚµãµÄÊýÖµ±È¸ù½ÚµãµÄÊýÖµÒª´óµÄ»°£¬ÔòÊÇС¸ù¶Ñ// 
	}
	if(ismax == true && ismin == true){
		printf("Not Heap");
	}
	else if(ismax == true){
		printf("Max Heap");
	}
	else if(ismin == true){
		printf("Min Heap");
	}
	
	return 0;
}

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值