有一段时间没刷题了,今晚刷了晴神为复试上机准备的模拟赛,将代码记录一下吧~
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;
}