算法提高 vertex cover(Dfs 搜索)

试题 算法提高 vertex cover

资源限制
时间限制:2.0s 内存限制:256.0MB
问题描述
  给定一个N个点M条边的无向图G(点的编号从1至N),问是否存在一个不超过K个点的集合S,使得G中的每条边都至少有一个点在集合S中。
输入格式
  输入的第一行包含一个整数T,表示数据的组数。
  接下来T组数据中:每组输入的第一行包含三个整数n, m, k,分别表示图的点数,边数,集合点数的最大值。接下来m行,每行2个正整数x,y,表示编号为 x 的节点与编号为 y 的节点间有一条边相连。
输出格式
  对于每组测试数据,若其存在解,则将解输出出来:第一行为一个整数t,表示所选点集的大小;第二行为t个整数,表示所选的点的编号。如果存在多组解,只要输出其中一种方案即可(会有special judge程序对你的输出进行检查)。
  若该组测试数据不包含解,则输出一个数-1(一行)。
样例输入
2
10 8 3
6 4
7 2
7 4
7 6
9 3
9 5
10 6
10 9
10 8 2
6 4
7 2
7 4
7 6
9 3
9 5
10 6
10 9
样例输出
3
6 7 9
-1
数据规模和约定
  对于80%的数据,满足 0   所有的数据满足 0  *****************************************************************************

题解

题目的意思就是,在一个结点数为n,边数为m的图中,挑不超过k个结点,使得这m条边至少有一个端点在集合k中。(结点数n不必理会,完全多余)

要挑k个结点,我们就按顺序,一条边一条边的判断,如果这条边的某个端点已经选中了,那
么无需操作,判断下一个;如果这条边的两个端点都没有选中,此时又有两种情况:1 已经
选了k个结点,此时不符合题意,及时返回 2 没有选满k个结点,那么就随机把两个端点的
一个选中,之后选中的结点数量加1,然后判断下一条边,直到最后一个结点,如果满足条
件,那么返回true,就找到满足条件的解了。(有多解,只需要输出一个可行解就行了。

AC代码如下:

#include
using namespace std;

struct edge{
	int x;
	int y;
	edge(int a=0,int b=0){x=a;y=b;}
};
edge V[5001];
bool vis[101];	//用来记录选中的结点
int N,M,K;
vector<int> chos;

bool dfs(int cur,int use){	//cur当前边的编号 use已经使用的结点的数量 
	if(cur==M)		//全部的边都已经满足条件了 
		return 1;
	if((!vis[V[cur].x]) && (!vis[V[cur].y])){	//该边的两个端点都没有选中 
		if(use==K)			//此时若不能再选点,则不符合题意,及时回溯 
			return 0;
			
		vis[V[cur].x]=1;		//选中一个端点 
		if(dfs(cur+1,use+1))	//往后递归 
			return 1;	
		vis[V[cur].x]=0;	//剔除这个端点 
				
		vis[V[cur].y]=1;		//试试另外一个端点 
		if(dfs(cur+1,use+1))
			return 1;
		vis[V[cur].y]=0;
	}
	else if(dfs(cur+1,use))	//该边的某个端点已经选中了,递归下一层 
		return 1;
	return 0;
}

int main(){
	int n;
	
	scanf("%d",&n);
	while(n--){
		memset(vis,0,sizeof(vis));
		chos.clear();
		
		scanf("%d%d%d",&N,&M,&K);
		for(int i=0;i<M;i++){
			scanf("%d%d",&V[i].x,&V[i].y);
		}
		
		if(dfs(0,0)){
			int ans=0;
			for(int i=1;i<=N;i++)
				if(vis[i]){
					chos.push_back(i);	//同时把选中的点放到chos中 
					ans++;
				}
			printf("%d\n",ans);
			for(int i=0;i<chos.size();i++)
				printf("%d ",chos[i]);
			printf("\n");
		}
		else
			printf("-1\n");
	}
	return 0;
}

PS。 编者一开始的时候,担心5000层的递归会爆栈,但是AC了,如有更好的解法,欢迎私信 ><

你可能感兴趣的:(蓝桥杯题库,题解)