PAT(甲)2018年秋季考试题目记录

7-1 Werewolf - Simple Version 

 这是道逻辑题,没太做过类似这种的题目,所以不是很擅长,这题卡了我四十分钟,而且是过掉2,3之后回头才过掉这题的,但其实想来这题还是很简单的。

看题目数据不大,而且狼人和人类中分别必有一人说谎,因此两重循环,每轮假设两个狼人其他均为人类,然后看他们说的话与对应角色的假设身份是否冲突,如果冲突,那么就用掉一次该角色阵营的说谎次数,由于每方只能说谎一次,假如出现了说谎次数不够,就产生冲突,该种假设肯定不成立;反之,直到最后,没产生冲突,而且两阵营的说谎次数必须耗尽,则该假设成立。

#include
using namespace std;

int n;
int sp[105];

int main(){
	scanf("%d",&n);
	memset(sp,0,sizeof(sp));
	for(int i = 1; i <= n; ++i)
		scanf("%d",&sp[i]);
	int good, wolf;
	int mark[105];
	for(int i = 1; i < n; ++i){
		for(int j = i+1; j <= n; ++j){//i j wolf
			memset(mark,1,sizeof(mark));
			mark[i] = mark[j] = -1;
			good = wolf = 1;
			int flag = 0;
			for(int k = 1; k <= n; ++k){//sp loop
				int tmp = sp[k], pos = abs(tmp);
				if((tmp > 0 && mark[pos] > 0) || (tmp < 0 && mark[pos] < 0)){
					//buguan
				}
				else{
					if(k == i || k == j){
						if(wolf == 1) wolf--;
						else {
							flag = 1;break;
						}
						
					}
					else{
						if(good == 1) good--;
						else {
							flag = 1;break;
						}
					}
				}
			}
			if(!flag && wolf == 0 && good == 0){
				printf("%d %d",i,j);
				return 0;
			}
				
		}
	}
	printf("No Solution");
	return 0;
}

 7-2 Dangerous Goods Packaging

这题有点意外,竟然用了个map就过了???我一开始看着很像虚点并查集,但是画了画忘了虚点并查基怎么写了,就想先暴力拿分再说,结果就过了。。。

思路简单明了,将冲突的两种make_pair作为key存入map中,查询的时候,前面输入中没有出现过的直接忽略,出现过的放入一个vector中,后来者就与所有已经存入的比较是否在map中存在这一对,如果存在就冲突。

#include
using namespace std;
int n,m;
map, int> mp;
int vis[100005];
int main(){
	scanf("%d%d",&n,&m);
	int a, b;
	for(int i = 0; i < n; ++i){
		scanf("%d%d",&a,&b);
		mp[make_pair(a,b)] = 1;
		mp[make_pair(b,a)] = 1;
		vis[a] = vis[b] = 1;
	}
	int k,num;
	for(int i = 0; i < m; ++i){
		scanf("%d",&k);
		vector list;
		int flag = 1;
		for(int j = 0; j < k; ++ j){
			scanf("%d",&num);
			if(flag == 1){
				if(vis[num] == 1){
				for(int t = 0; t < list.size(); ++t){
					if(mp[make_pair(num,list[t])] == 1){
						flag = 0;
						break;
						}
					}
				if(flag)
					list.push_back(num);
				}
			}
			
		}
		if(flag)
			printf("Yes\n");
		else
			printf("No\n");
	}
	return 0;
}

7-3 Travelling Salesman Problem (图)

这题更加直白简单,完全就是个代码题吧,没啥好说的。

#include
using namespace std;
const int MAX = 100000;
int N, M;
int g[205][205];
void init(){
	for(int i = 0; i < N+2; ++i){
		for(int j = 0; j < N+2; ++j){
			g[i][j] = g[j][i] = MAX;
		}
	}
}
struct Ans{
	int path, dis;
	
	bool operator < (const Ans &a) const{
		return dis < a.dis;
	}
};
vector dist;

int main(){
	scanf("%d%d",&N,&M);
	init();
	int a, b, dis;
	for(int i = 0; i < M; ++i){
		scanf("%d%d%d",&a,&b,&dis);
		g[a][b] = g[b][a] = dis;
	}
	int k, n;
	scanf("%d",&k);
	for(int cnt = 1; cnt <= k; ++cnt){
		scanf("%d",&n);
		int tol = 0,origin, pre, cur, flag = 1;
		int vis[N+5];
		memset(vis,0,sizeof(vis));
		scanf("%d",&pre);
		origin = pre;
		vis[pre] = 1;
		for(int i = 1; i < n-1; ++i){
			scanf("%d",&cur);
			if(g[pre][cur] != MAX){
				tol += g[pre][cur];
				vis[cur] += 1;
				pre = cur;
			}
			else flag = -1;
		}
		scanf("%d",&cur);
		if(flag == -1 || cur != origin){//not cycle
			if(flag == -1)
				printf("Path %d: NA (Not a TS cycle)\n",cnt);
			else
				printf("Path %d: %d (Not a TS cycle)\n",cnt,tol+g[pre][cur]);
		}
		else{
			for(int j = 1; j <= N; ++j){
				if(vis[j] == 0){
					flag = -1;
				}
				else if(vis[j] > 1 && flag != -1){
					flag = 2;
				}
			}
			if(flag == -1)
				printf("Path %d: %d (Not a TS cycle)\n",cnt,tol+g[pre][cur]);
			else if(flag == 2){
				printf("Path %d: %d (TS cycle)\n",cnt,tol+g[pre][cur]);
				Ans tmp;
				tmp.path = cnt;
				tmp.dis = tol+g[pre][cur];
				dist.push_back(tmp);
			}
				
			else{
				printf("Path %d: %d (TS simple cycle)\n",cnt,tol+g[pre][cur]);
				Ans tmp;
				tmp.path = cnt;
				tmp.dis = tol+g[pre][cur];
				dist.push_back(tmp);
			}
				
		}
	}
	sort(dist.begin(),dist.end());
	printf("Shortest Dist(%d) = %d\n",dist[0].path,dist[0].dis);
	return 0;
}

 7-4 LCA in a Binary Tree (LCA+中序先序建二叉树)

其实我至今没想明白,为什么我在考场上一个小时没建出树来,虽说回来后写完了建树的方法,最后没拿满分,但是90+是妥妥的,当时出来真的心态崩了,感觉对不起前面三道题的满分。

这题有两种方法,一种建立二叉树,然后搜,我自己没有想出很好的搜索的方法,因此最后两个case超内存了,反正网上建树的方法多得是,不赘述了。

第二种方法就是不建树,通过中序里子树和其根的关系来搞定,代码简单,易懂。

我们只需要控制三个变量:inl(中序的左边界),inr(中序右边界),pre_root(先序的根结点位置)

然后会有三种情况:1.u,v在中序里都在根的左边或者右边,这就说明他们必然有下一个公共的根。

                                 2.u,v在中序里根的两边,那么这个根就是他们的公共根。

                                 3.u或v位置等于当前根的位置,那么相同位置的就是另一个的根。

LCA的代码:

#include
using namespace std;

int n,m,k;
vector inorder;
vector preorder;
map key2pos;
map vis;

void lca(int inl, int inr, int pre_root, int u, int v){
	if(inl > inr) return;
	int in_root = key2pos[preorder[pre_root]], uindex = key2pos[u], vindex = key2pos[v];
	if(uindex < in_root && vindex < in_root){//left subtree
		lca(inl,in_root - 1,pre_root+1,u,v);
	}
	else if((uindex < in_root && vindex > in_root) || (uindex > in_root && vindex < in_root)){//in_root is root
		printf("LCA of %d and %d is %d.\n", u, v, inorder[in_root]);
	}
	else if(uindex > in_root && vindex > in_root){//right subtree{
		lca(in_root+1,inr,pre_root+1+in_root-inl,u,v);
	}
	else{
		if(uindex == in_root) printf("%d is an ancestor of %d.\n", u, v);
		else printf("%d is an ancestor of %d.\n", v, u);
	}	
}

int main(){
	scanf("%d%d",&m,&n);
	int a;
	for(int i = 0; i < n; ++i){
		scanf("%d",&a);
		inorder.push_back(a);
		key2pos[a] = i;
		vis[a] = 1;	
	}
	for(int i = 0; i < n; ++i){
		scanf("%d",&a);
		preorder.push_back(a);
	}
	int u, v;
	for(int i = 0; i < m; ++i){
		scanf("%d%d",&u,&v);
		if (!vis[u] && !vis[v])
        {
            printf("ERROR: %d and %d are not found.\n",u,v);
        }
        else
        if (!vis[u])
        {
            printf("ERROR: %d is not found.\n",u);
        }
        else
        if (!vis[v])
        {
            printf("ERROR: %d is not found.\n",v);
        }
        else
        {
        	lca(0,n-1,0,u,v);
        }
	}
	return 0;
}

建树搜索的代码,最后两个case超内存,但主要为了记录下建树,防止下回还TM一小时建不出树:

#include
using namespace std;

int n,m,k;
struct Node{
	int h, left, right, data;
	Node(){
	}
	bool operator < (const Node &a) const{
		return h < a.h;
	} 
};
vector inorder;
vector preorder;
Node tree[10005];
map vis;
vector ans;

int build(int prel, int prer, int inl, int inr, int pos, int height){
	if(pos >= n) return -1;
	tree[pos].h = height;
	tree[pos].data = preorder[pos];
	tree[pos].left = tree[pos].right = -1;
	for(int i = inl; i <= inr; ++i){
		if(inorder[i] == preorder[prel]){
			if(i > inl){
				tree[pos].left = build(prel+1,prel+i-inl,inl,i-1,prel+1,height+1);
			}
			if(i < inr){
				tree[pos].right = build(i-inl+prel+1,prer,i+1,inr,i-inl+prel+1,height+1);
			}
		}
	}
	return pos;
}


void finds(int x, int pos, vector path, int &flag){
	if(x == tree[pos].data){
		path.push_back(tree[pos]);
		ans.insert(ans.end(),path.begin(),path.end());
		flag = 1;
		return;
	}
	if(flag == 1) return;
	path.push_back(tree[pos]);
	if(tree[pos].left != -1)
		finds(x,tree[pos].left,path,flag);
	if(flag == 1) return;
	if(tree[pos].right != -1)
		finds(x,tree[pos].right,path,flag);
	if(flag == 1) return;
}

int main(){
	scanf("%d%d",&m,&n);
	int a;
	for(int i = 0; i < n; ++i){
		scanf("%d",&a);
		inorder.push_back(a);
		vis[a] = 1;	
	}
	for(int i = 0; i < n; ++i){
		scanf("%d",&a);
		preorder.push_back(a);
	}
	build(0,n-1,0,n-1,0,1);
	int u, v;
	for(int i = 0; i < m; ++i){
		scanf("%d%d",&u,&v);
		if (!vis[u] && !vis[v])
        {
            printf("ERROR: %d and %d are not found.\n",u,v);
        }
        else
        if (!vis[u])
        {
            printf("ERROR: %d is not found.\n",u);
        }
        else
        if (!vis[v])
        {
            printf("ERROR: %d is not found.\n",v);
        }
        else
        {
        	int flag = 0;
        	vector tmp1;
            finds(u,0,tmp1,flag);
            vector tmp2;
            flag = 0;
            finds(v,0,tmp2,flag);
            sort(ans.begin(),ans.end());
            int res;
            for(int i = 0; i < ans.size(); i += 2){
            	if(i != ans.size()-1 && ans[i].data == ans[i+1].data){
            		res = ans[i].data;
            	}
            }
            if (res == u) printf("%d is an ancestor of %d.\n",u,v);
			else if (res == v) printf("%d is an ancestor of %d.\n",v,u);
			else
            printf("LCA of %d and %d is %d.\n",u,v,res);
            ans.clear();
        }
	}
	return 0;
}

甲级其实完全没有有难度的算法,大部分考的还是数据结构的基础,这次在二叉树上翻了车,想来还是不够扎实吧,12月一定要拿个高分啊。

你可能感兴趣的:(树,PAT,数据结构与算法,图论,思维,逻辑)