2017-9-17 PAT考试记

昨天去考pat,居然四题都一次ac了~~小激动,之前自己模拟测都是 八九十,有些测试用例死活想不到错误原因。

第一题 1132. Cut Integer,简单题。测试的时候想到了除零的情况。

#include <cstdio>
#include <cstdlib>
#include <vector>
#include <cstring>
#include <cmath>

using namespace std;
/*
3
167334
2333
12345678

3
10
2333
12345678
*/
void split( int num, int &a, int &b)
{
	int digits=0, n=num;
	while( n > 0 )
	{
		digits++;
		n /= 10;
	}
	
	int mod = pow(10, digits/2);
	a = num%mod;
	b = num/mod;
	//printf("digit = %d %d %d\n", digits, a, b);
}
int main()
{
	int n;
	scanf("%d", &n);
	int num, a,b;
	for (int i=0; i<n; i++)
	{
		scanf("%d", &num);
		split( num, a, b);
		if ( a==0 || b==0 )printf("No\n");
		else if ( num % a !=0 ) printf("No\n");
		else{
			num /= a;
			if( num %b != 0) printf("No\n");
			else 			 printf("Yes\n");
		}
	}
	
	return 0;
}

 

第二题 1133. Splitting A Linked List  链表的操作题。题目输入已经定好了地址,杜绝了直接用stl的list。 地址范围不大,所以直接用二维数组实现链表。

#include <cstdio>
#include <cstdlib>
#include <vector>
#include <cstring>
#include <cmath>

using namespace std;
#define maxn 100001
int head,n,k;
int List[maxn][2];

void print( int n)
{
	while( n != -1)
	{
		printf("%05d %d ", n, List[n][0], List[n][1] );
		if (List[n][1] == -1)
			printf("-1\n");
		else
			printf("%05d\n", List[n][1]);
		n = List[n][1];
	}
	//printf("NULL\n");
}
int main()
{
	scanf("%d %d %d", &head, &n, &k);
	int a,d,next;
	for (int i=0; i<n; i++)
	{
		scanf("%d %d %d", &a, &d, &next);
		List[a][0] = d;
		List[a][1] = next;
	}
	//找负数
	int *cur = &head, newList = -1, *newTail=&newList;
	while( *cur >= 0 ) //未到达链表尾 
	{
		//printf("====%d\n", List[*cur][0]);
		if( List[*cur][0] < 0 ){
			int tmp = *cur;
			*cur = List[tmp][1]; // 拆下节点tmp, 续上链表 
			
			List[tmp][1] = *newTail;
			*newTail = tmp; //节点tmp 接到新链表 
			newTail = &List[tmp][1];
		}
		else
			cur = &List[*cur][1];
	}

	//找<=k的
	cur = &head; //从头再找 
	while( *cur >= 0 ) //未到达链表尾 
	{
		//printf("====%d\n", List[*cur][0]);
		if( List[*cur][0] <= k ){
			int tmp = *cur;
			*cur = List[tmp][1]; // 拆下节点tmp, 续上链表 
			
			List[tmp][1] = *newTail;
			*newTail = tmp; //节点tmp 接到新链表 
			newTail = &List[tmp][1];
		}
		else
			cur = &List[*cur][1];
	}
	
	// 剩下的拼上去 
	*newTail = head; 
	print(newList);
	return 0;
}

 

第三题  1134. Vertex Cover 读题有点磕磕碰碰 is incident to 不理解是什么意思。只能根据样例连猜带蒙。

大意就是给一个图和若干个查询点集。

对每个点集里面的点是否和图里面的所有边都沾边。 也就是图的任一边的必须有端点在点集内。

所以思路就出来了,计算点集内的每个节点 V, 从V 出发能有多少边。去重之后加在一起的边数等于整个图的边数,就是Yes。否则No。

 

 #include <cstdio>
#include <cstdlib>
#include <vector>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;
int n,m;//节点数, 边数
vector<short> g[10001]; //short 足够表示 32768
bool used[10001];  // 查询时,判断这个节点是否用过了

int caledge( const vector<short>& q)
{
	int sum = 0, v;
	for( int i=0; i<q.size(); i++)
	{
		v = q[i];
		for(int w=0; w<g[v].size(); w++ )
		{
			if ( used[ g[v][w] ] == false ) ++sum;
		}
		used[ v ] = true;
		//printf("q=%d sum=%d\n", v, sum);
	}
	
	return sum;
}

int main()
{
	scanf("%d %d", &n, &m);
	short a,b, tmp;
	for (int i=0; i<m; i++) //建立图 
	{
		scanf("%hd %hd", &a, &b);
		g[a].push_back(b);
		g[b].push_back(a);
	}
	
	scanf("%d", &a); //a个查询
	vector<short> qvex; //待查询点集 
	for(int i=0; i<a; i++)
	{
		scanf("%hd", &b); //点集大小
		for( int j=0; j<b; j++)
		{
			scanf("%hd", &tmp);
			qvex.push_back(tmp);
		}
		
		if (caledge( qvex ) == m ){
			printf("Yes\n");
		}
		else
		{
			printf("No\n");
		}
		
		qvex.clear();
		memset(used, 0, sizeof(used) ); 
	} 
	
	return 0;
}

/*

10 11
8 7
6 8
4 5
8 4
8 1
1 2
1 4
9 8
9 1
1 0
2 4
5
4 0 3 8 4
6 6 1 7 5 4 9
3 1 8 4
2 2 8
7 9 8 7 6 5 4 2

*/

 

 

 

第四题 1135. Is It A Red-Black Tree 这题是标题党,一开始吓了一跳,居然考了红黑树,完全不会啊怎么办。

后来看了题目,发现只是判断输入的二叉搜索树是不是满足红黑的属性。

根据BST的先序还原出BST的树结构以及每个节点的红黑属性。

再来就是按题目说明的红黑树的条件逐条检查,看看是否完全符合。

(1) Every node is either red or black.
(2) The root is black.
(3) Every leaf (NULL) is black.
(4) If a node is red, then both its children are black.
(5) For each node, all simple paths from the node to descendant leaves contain the same number of black nodes.

条件一不用检查,本来我们的节点就只能要么红要么黑,还原出来的树肯定是符合的。

条件二三说明 红黑树一定是黑色叶节点的。毕竟null的节点也算黑色。

条件四就是红色节点不能相邻,递归遍历每个节点,检查红节点的两个儿子就好了。

条件五略复杂,从任一节点出发到他的后继叶子,不管走哪条路径,黑节点数目是相同的。想了想,和计算树高度有点像。只不过这里计算的是黑色高度

思路就来了,从根节点递归到叶子,递归返回时节点是黑色就加1,否则加0。注意叶节点一定是null,是黑色。

然后在逐层计算的时候发现有某一节点的左右子树的黑色高度不一致,就可以直接返回结果了不需要继续算。

 

 

#include <cstdio>
#include <cstdlib>
#include <vector>
#include <cstring>
#include <cmath>

using namespace std;
struct rbt{
	int d, isred;
	rbt *left,*right;
	rbt( int data=0, rbt * l=NULL, rbt * r=NULL)
	{
		left = l, right=r;
		setdata(data);
	}
	void setdata(int data){
		isred = data<0;  //负数表示红色节点
		d     = data<0?-data:data;
	}
};
bool isred( rbt* p ) //NULL节点算黑色 
{
	if( p )return p->isred;
	return 0;
}
// 区间 [l, h)
void buildtree(rbt*&subroot, int preorder[], int l, int h)
{
	if( l>=h ) return; 
	subroot = new rbt(preorder[l]);
	int mid=l+1;
	for( ; mid<h; mid++)
	{
		if ( abs(preorder[mid] ) > subroot->d ) break; //根据先序分割左右子树 
	}
	buildtree( subroot->left, preorder, l+1, mid );
	buildtree( subroot->right, preorder, mid, h );
}
void preShow( rbt*subroot )
{
	if ( subroot == NULL ) return ;
	printf("%d %d\n", subroot->d, subroot->isred);
	preShow( subroot->left );
	preShow( subroot->right );
}

//检查红节点的两儿子 
void checkRedChildren( rbt*subroot, bool&ret ){
	if ( ret == true )return ;
	
	if ( subroot == NULL ) return ;
	if ( isred(subroot) ) 
	{
		if (isred(subroot->left) || isred(subroot->right) )
		{
			ret = true;
			return;
		}
	}
	checkRedChildren(subroot->left, ret);
	checkRedChildren(subroot->right, ret);
}


//

int checkBlackNum(rbt*subroot, bool&ret)
{
	if(ret == true) 	 return 1;
	if( subroot == NULL )return 1;
	int leftB, rightB, isBlack = !isred(subroot);
	
	leftB =  isBlack + checkBlackNum(subroot->left, ret);
	rightB = isBlack + checkBlackNum(subroot->right, ret);
	
	if (leftB != rightB)
	{
		ret = true;
	}
	return leftB; 
} 
 
bool checkRB( rbt*root )
{
	if ( root->isred )  return false; //根节点必须是黑的 
	
	bool ret=false;
	checkRedChildren(root, ret);
	if ( ret == true )  return false; //红节点有红儿子,不是红黑树 
	
	checkBlackNum (root, ret);
	if ( ret == true ) return false; //节点到叶子的黑色数目不等 
	return true; 
}
int main()
{
	int k,n, t;
	scanf("%d", &k);
	while( k-- )
	{
		scanf("%d", &n);
		int preorder[n];
		for ( int i=0; i<n; i++)
		{
			scanf("%d",preorder+i); //万一输入里面有0呢,要处理 
		}
		rbt* root=NULL;
		buildtree( root, preorder, 0, n );
	//	preShow(root);
	
		if( checkRB(root) ) printf("Yes\n");
		else  printf("No\n");
	}

	return 0;
}
/*
3
9
7 -2 1 5 -4 -11 8 14 -15
9
11 -2 1 -7 5 -4 8 14 -15
8
10 -7 5 -6 8 15 -11 17

*/

/*
红色节点的相邻节点一定是黑色.
黑色的可以和黑色的相邻 
*/

 

 

 

用时: 

1:30开考,然后据说新的pat系统被限流了,导致拥堵。后来改到用浏览器提交,2:45正式开始~~

其实感觉挺好的,1:30正是困的时候,中间休息一会缓过来了,再敲个最小堆,矩阵乘法什么的热热身就进入状态了~~

第一题 15min

第二题 30min

第三题 40~50min

第四题 60+min

最后还有半小时结余~~撒花完结本日。

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值