2019年3月8日晴神浙大机试模拟赛之概念题

本文精选了算法竞赛中的四个经典问题:边覆盖、极大独立集、稳定婚姻问题和笛卡尔树,提供了详细的题目描述和解决方案,包括代码实现,旨在帮助读者理解和掌握相关算法知识。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

有一段时间没刷题了,今晚刷了晴神为复试上机准备的模拟赛,将代码记录一下吧~

A 边覆盖

Problem Description

对一个给定的无向图G(V,E),边集E'是E的子集。如果V中的所有顶点都在E'中出现过,那么称边集E'是图G的一个边覆盖(Edge Cover)。
(以上定义引自https://en.wikipedia.org/wiki/Edge_cover

根据上面的定义,请判断一些给定的边集是否是给定的无向图的边覆盖。

Input

每个输入文件一组数据。

第一行为两个整数N、M(1<=N<=500, 1<=M<=N*(N-1)/2),分别表示无向图的顶点数和边数。假设图上的顶点编号为从1到N。

接下来M行,每行两个正整数u、v(1<=u,v<=N, u!=v),分别表示一条无向边的两个端点。数据保证没有重边。

接着一个正整数K(K<=10),表示查询的个数。

然后是K个查询,每个查询第一行为一个正整数L(L<=M),表示欲查询边集E'中的边数;接下来L行,每行两个整数,表示边集E'中的一条边。数据保证E'一定是E的子集。

Output

每个查询一行,如果欲查询边集E'不是图G的边覆盖,那么输出No;否则输出Yes

程序 :

#include <cstdio>
#include <set>
using namespace std;
int road[501][501];
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i = 0; i < m; i++)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		road[a][b] = road[b][a] = 1;
	}
	int k;
	scanf("%d",&k);
	while(k--)
	{
		int l;
		scanf("%d",&l);
		set<int> st;
		for(int i = 0; i < l; i++)
		{
			int a,b;
			scanf("%d%d",&a,&b);
			st.insert(a);
			st.insert(b);
		}
		if(st.size() == n)
			printf("Yes\n");
		else 
			printf("No\n");
	}
	return 0;
}

B 极大独立集

Problem Description

对一个给定的无向图G(V,E),点集V'是V的子集。如果V'中的任意两个顶点之间都没有边,就称点集V'是图G的独立集(Independent Set)。在此基础上,如果往V'中添加任何一个在V中但不在V'中的顶点,都会使V'变成非独立集,那么就称V'是图G的极大独立集(Maximal Independent Set)。
(以上定义引自https://en.wikipedia.org/wiki/Independent_set_(graph_theory)

根据上面的定义,请判断一些给定的点集是否是给定的无向图的极大独立集。

Input

每个输入文件一组数据。

第一行为两个整数N、M(1<=N<=500, 1<=M<=N*(N-1)/2),分别表示无向图的顶点数和边数。假设图上的顶点编号为从1到N。

接下来M行,每行两个正整数u、v(1<=u,v<=N, u!=v),分别表示一条无向边的两个端点。数据保证没有重边。

接着一个正整数K(K<=10),表示查询的个数。

然后是K个查询,每个查询第一行为一个正整数L(L<=N),表示欲查询点集V'的顶点个数;第二行为用空格隔开的L个正整数,表示V'中的顶点编号。数据保证V'一定是V的子集。

Output

每个查询一行,如果欲查询的点集不是图G的独立集,那么输出Not an Independent Set;如果欲查询的点集是图G的独立集但不是极大独立集,那么输出Not Maximal;如果欲查询的点集是图G的极大独立集,输出Yes

程序:

#include <cstdio>
#include <set>
#include <vector>
using namespace std;
int road[501][501];
int n,m;
bool isDep(vector<int> v)
{
	for(int i = 0; i < v.size(); i++)
	{
		for(int j = i + 1; j < v.size(); j++)
		{
			if(road[v[i]][v[j]])
				return false;
		}
	}
	return true;
}
bool isMax(vector<int> v)
{
	set<int> st;
	for(int i = 0; i < v.size(); i++)
		st.insert(v[i]);
	for(int i = 1; i <= n; i++)
	{
		bool flg = true;
		if(st.count(i))
		   continue;
		for(int j = 0; j < v.size(); j++)
		{
			if(road[i][v[j]])
			{
				flg = false;
				break;
			}
		}
		if(flg)
			return false;
	}
	return true;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i = 0; i < m; i++)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		road[a][b] = road[b][a] = 1;
	}
	int k;
	scanf("%d",&k);
	while(k--)
	{
		int l;
		scanf("%d",&l);
		vector<int> v;
		for(int i = 0; i < l; i++)
		{
			int a;
			scanf("%d",&a);
			v.push_back(a);
		}
		if(!isDep(v))
			printf("Not an Independent Set\n");
		else if(!isMax(v))
			printf("Not Maximal\n");
		else
			printf("Yes\n");
	}
	return 0;
}

C 稳定婚姻问题

Problem Description

有两个点集V1和V2,点集中的顶点个数均为N。现在对V1和V2中的点建立一对一映射关系,也就是说,V1中的每个点对且只对V2中的一个点建立连接关系,V2中的每个点也对且只对V1中的一个点建立连接关系。这样这两个点集间就有N个连接。

已知点集V1中的每个点都对V2中的所有点有一个优先顺序,点集V2中的每个点也对V1中的所有点有一个优先顺序。例如V1中有两个点a1、a2,V2中有两个点b1、b2,那么a1会希望V2中与它连接的点的优先顺序是比如b2 > b1,a2会希望V2中与它相连接的点的优先顺序是比如b1 > b2,b1会希望V1中与它连接的点的优先顺序是比如a1 > a2,b2会希望V1中与它相连接的点的优先顺序是比如a1 > a2。

对给定的一对一映射关系来说,如果存在V1和V2中没有连接关系的一对点(ai, bj),满足(1)对ai来说,bj的优先顺序高于ai当前的连接对象(2)对bj来说,ai的优先顺序也高于bj当前的连接对象,那么我们称这组映射关系是不稳定的;而如果V1和V2中没有连接关系的任意点对(ai, bj)都不满足上面的条件,则称这组映射关系是稳定的。

(以上定义总结自https://en.wikipedia.org/wiki/Stable_marriage_problem

现在给出所有点希望对方点集的点的优先顺序,判断一些映射关系是否是稳定的。

Input

每个输入文件一组数据。

第一行为一个正整数N(N <= 500),表示每个点集中都有N个点。假设每个点集中的点的编号都是从1到N。

接下来N行,每行N个整数,表示点集V1中的点希望V2中与它连接的点的优先顺序。其中第2行为编号为1的点希望V2中与它连接的点的优先顺序,第3行为编号为2的点希望V2中与它连接的点的优先顺序……第N+1行为编号为N的点希望V2中与它连接的点的优先顺序。每行均按优先级从高到低的顺序给出V2中的点的编号。

再接下来N行,每行N个整数,表示点集V2中的点希望V1中与它连接的点的优先顺序。其中第N+2行为编号为1的点希望V1中与它连接的点的优先顺序,第N+3行为编号为2的点希望V1中与它连接的点的优先顺序……第2N+1行为编号为N的点希望V1中与它连接的点的优先顺序。每行均按优先级从高到低的顺序给出V1中的点的编号。

然后是一个一个正整数K(K<=10),表示查询个数。

每个查询为一组映射关系,共N行,每行两个整数i和j,表示V1中编号为i的点与V2中编号为j的点互为连接对象。数据保证给出的映射关系一定是一对一的。

Output

每行输出一个查询的结果,如果当前查询的映射关系是稳定的,那么输出Stable,否则输出Not Stable

程序:

#include <cstdio>
#include <vector>
#include <utility>
#include <map>
#include <unordered_map>
using namespace std;
vector<unordered_map<int,int> > v1(501);
vector<unordered_map<int,int> > v2(501);
int main()
{
	int n;
	scanf("%d",&n);
	for(int i = 1; i <= n; i++)
	{
		for(int j = 0; j < n; j++)
		{
			int a;
		    scanf("%d",&a);
		    v1[i][a] = j;
		}
	}
	for(int i = 1; i <= n; i++)
	{
		for(int j = 0; j < n; j++)
		{
			int a;
		    scanf("%d",&a);
		    v2[i][a] = j;
		}
	}
	int k;
	scanf("%d",&k);
	while(k--)
	{
		unordered_map<int,int> m1;
		unordered_map<int,int> m2;
		for(int i = 0; i < n; i++)
		{
			int a,b;
			scanf("%d%d",&a,&b);
			pair<int,int> pr;
			pr.first = a;
			pr.second = b;
			m1[a] = b;
			m2[b] = a;
		}
		bool flag = false;
		for(int i = 1; i <= n; i++)
		{
			for(int j = 1; j <= n; j++)
			{
				int bj = m1[i];//原配
				int ai = m2[j];//原配
				if(v1[i][j] < v1[i][bj] && v2[j][i] < v2[j][ai])
				{
					flag = true;
					printf("Not Stable\n");
					break;
				}					
			}
			if(flag) break;
		}
		if(!flag)
			printf("Stable\n");
	}
	return 0;
}

 D 笛卡尔树

Problem Description

对一棵二叉树来说,如果树上的每个结点有两个值K、V,满足
(1)以K为视角时这棵二叉树满足二叉查找树的性质,即对每个结点,左子树所有结点的K值小于该结点的K值小于右子树所有结点的K值;
(2)以V为视角时这棵二叉树满足堆的性质,即每个结点的V值都大于子树所有结点的V值(或都小于子树所有结点的V值)。
那么就称这棵二叉树是笛卡尔树。
(以上定义引自https://en.wikipedia.org/wiki/Cartesian_tree

现在给定一棵二叉树,请判断其是否是笛卡尔树。

注意,笛卡尔树只是满足堆的性质,不代表一定是完全二叉树。

Input

每个输入文件一组数据。

第一行为一个正整数N(2<=N<=1024),表示二叉树上的结点数目。假设结点编号为从1到N。

第二行为N个正整数,表示1到N号结点的K值。数据保证每个值唯一,且不超过10000。

第三行为N个正整数,表示1到N号结点的V值。数据保证每个值唯一,且不超过10000。

接下来N行,按编号从1号到N号的顺序给出每个结点的子结点信息。每行两个整数,分别表示当前结点的左结点编号和右结点编号。如果左结点或右结点为空,则记为-1。

Output

如果该二叉树是笛卡尔树,那么输出第一行YES,然后在第二行输出MIN HEAP或者MAX HEAP,分别表示该笛卡尔树的V值满足小顶堆或大顶堆的性质。

如果该二叉树不是笛卡尔树,那么输出第一行NO,然后在第二行输出错误信息,即如果K值不满足二叉查找树的性质,那么输出NOT BST;如果V值不满足堆的性质,那么输出NOT HEAP;如果K值和V值都不满足,那么输出NOT BST AND NOT HEAP

程序:

#include <cstdio>
#include <climits>
using namespace std;
struct node
{
	int k,v;
};
struct Tnode
{
	int left,right;
};
struct node a[1025];
struct Tnode b[1025];
int child[1025];
bool isBST1(int root,int minval,int maxval)
{
	if(root == -1) return true;
	if(a[root].k > minval && a[root].k < maxval)
		return isBST1(b[root].left,minval,a[root].k) && 
	           isBST1(b[root].right,a[root].k,maxval);
	return false;
}
bool isBST(int root)
{
	return isBST1(root,INT_MIN,INT_MAX);
}
bool isMinHeap(int root)
{
	if(root == -1) return true;
	int l = b[root].left;
	int r = b[root].right;
	if(l == -1 && r == -1)
		 return true;
	else if(l == -1 && r != -1)
	{
		if(a[root].v < a[r].v)
			return isMinHeap(r);
		else return false;
	}
	else if(l != -1 && r == -1)
	{
		if(a[root].v < a[l].v)
			return isMinHeap(l);
		else return false;
	}
	else if(l != -1 && r != -1)
	{
		if(a[root].v < a[l].v && a[root].v < a[r].v)
			return isMinHeap(l)&&isMinHeap(r);
		else return false;
	}
}
bool isMaxHeap(int root)
{
	if(root == -1) return true;
	int l = b[root].left;
	int r = b[root].right;
	if(l == -1 && r == -1)
		 return true;
	else if(l == -1 && r != -1)
	{
		if(a[root].v > a[r].v)
			return isMaxHeap(r);
		else return false;
	}
	else if(l != -1 && r == -1)
	{
		if(a[root].v > a[l].v)
			return isMaxHeap(l);
		else return false;
	}
	else if(l != -1 && r != -1)
	{
		if(a[root].v > a[l].v && a[root].v > a[r].v)
			return isMaxHeap(l) && isMaxHeap(r);
		else return false;
	}
}
int main()
{
	int n;
	scanf("%d",&n);
	for(int i = 1; i <= n; i++)
		scanf("%d",&a[i].k);
	for(int i = 1; i <= n; i++)
		scanf("%d",&a[i].v);
	for(int i = 1; i <= n; i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		if(x != -1)
			child[x] = 1;
		if(y != -1)
			child[y] = 1;
		b[i].left = x;
		b[i].right = y;
	}
	int root = 0;
	for(int i = 1; i <= n; i++)
		if(child[i] == 0)
		{
			root = i;
			break;
		}
	if(isBST(root))
	{
		if(isMinHeap(root))
		{
			printf("YES\n");
			printf("MIN HEAP\n");
		}
		else if(isMaxHeap(root))
		{
			printf("YES\n");
			printf("MAX HEAP\n");
		}
		else 
		{
			printf("NO\n");
			printf("NOT HEAP\n");
		}
	}
	else 
	{
		if(isMinHeap(root))
		{
			printf("NO\n");
			printf("NOT BST\n");
		}
		else if(isMaxHeap(root))
		{
			printf("NO\n");
			printf("NOT BST\n");
		}
		else 
		{
			printf("NO\n");
			printf("NOT BST AND NOT HEAP\n");
		}
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值