PAT 1134
C++
版
1.题意
输入:给出一个无向图的边节点信息;给出数组待查询顶点的集合
让你判断图中的任一条边的顶点是否都在这个顶点的集合中?如果都在则称为vertex cover
,否则不是。
2.分析
- 暴力求解
直接根据输入新建一个结构体数组,其中保留的是每条边left,right左右两个节点,以及一个访问标志位。在输入节点集合之后,使用双重循环遍历一遍,表示边的访问信息。最后再使用一个循环,找出是否存在未访问的边,如果有,则输出No,否则输出Yes。
3.代码
- 暴力求解
#include<cstdio>
#include<iostream>
using namespace std;
struct edge{
int left,right;//一条边的左右两个顶点
int visit = 0 ;//标识这条边是否访问过,初始值为0
};
edge e[10005];
int main(){
int N,M;
scanf("%d %d",&N,&M);
int i,j,x;
for(i = 0;i< M;i++){
scanf("%d%d",&e[i].left,&e[i].right);
}
int K;//待查询数
scanf("%d",&K);
int verNum;//表示待查询的顶点集合数
int verSet[10005];
for(i = 0;i< K;i++){
scanf("%d",&verNum);
for(j = 0;j< verNum;j++){
scanf("%d",&verSet[j]);//输入待查询的每个vertex
}
//开始进行处理
//外层循环代表的是
for( x = 0; x < M; x++ ){
for(j = 0;j < verNum;j++){
if(e[x].left == verSet[j] || e[x].right == verSet[j]) {
e[x].visit = 1;//置为1
}
}
}
for( x = 0;x < M ;x++){
if(e[x].visit == 0){//代表仍然有不满足的情况
break;
}
e[x].visit = 0;//reset
}
if(x == M) cout <<"Yes"<<endl;
else cout<<"No"<<endl;
}
}
但是这个代码的执行结果是存在两组 运行超时 的用例。显然不是最优的解决办法。
4.执行结果
5.优化记录
在使用数组碰到运行超时的问题时,就需要考虑到set
了。这真是个好东西。解题思想没有变化,只不过是将int verSet[10005];
替换成set<int> verSet;
然后将相应的数组操作替换成 set 操作即可。得到的代码如下:
#include<cstdio>
#include<iostream>
#include<set>
using namespace std;
struct edge{
int left,right;//一条边的左右两个顶点
int isVisit = 0;//表示是否访问过
};
edge e[10005];
int main(){
int N,M;
scanf("%d %d",&N,&M);
int i,j,x;
int left,right;
for(i = 0;i< M;i++){
scanf("%d%d",&e[i].left,&e[i].right);
}
int K;//待查询数
scanf("%d",&K);
int verNum;//表示待查询的顶点集合数
set<int> verSet; //待查询顶点集
int vertex;//每个顶点
for(i = 0;i< K;i++){
scanf("%d",&verNum);
for(j = 0;j< verNum;j++){
scanf("%d",&vertex);//输入待查询的每个vertex
verSet.insert(vertex);//插入到set中
}
//开始进行处理
for( x= 0; x<M;x++ ){
if(verSet.find(e[x].left)==verSet.end()
&& verSet.find(e[x].right)==verSet.end() ){
break;
}
}
if(x == M) cout <<"Yes"<<endl;
else cout<<"No"<<endl;
verSet.clear();//clear set
}
}
- 测试用例
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
- 执行结果
一遍AC。