当前位置: 代码迷 >> 综合 >> 算法提高 vertex cover(Dfs 搜索)
  详细解决方案

算法提高 vertex cover(Dfs 搜索)

热度:51   发布时间:2023-12-10 07:49:55.0

试题 算法提高 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<n<=20, m<=200, k<=20。
  所有的数据满足 0<n<=100, m<=5000, k<=20。
 *****************************************************************************

题解

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

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

AC代码如下:

#include<bits/stdc++.h>
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");}elseprintf("-1\n");}return 0;
}

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