试题 算法提高 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。
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
struct Node{
int x,y;
}a[5005];
int n,m,k;
int vis[105];
vector<int> q;
bool dfs(int cur,int use) //当前的编号,使用节点个数
{
if(cur == m)
{
return 1;
}
// 这条边的两个点都没选中
if(!vis[a[cur].x] && !vis[a[cur].y])
{
if(use == k)
{
return 0;
}
vis[a[cur].x] = 1;//现任意选中一个点
if(dfs(cur+1,use+1)) //继续找下一层
{
return 1;
}
vis[a[cur].x] = 0;//回归现场
vis[a[cur].y] = 1;
if(dfs(cur+1,use+1))
{
return 1;
}
vis[a[cur].y] = 0;
}
else if(dfs(cur+1,use)) //该边的某个端点已经被选中
{
return 1;
}
return 0;
}
int main(void)
{
int t;
cin>>t;
while(t--)
{
memset(vis,0,sizeof(vis));
cin>>n>>m>>k;
for(int i = 0;i < m;i++)
{
cin>>a[i].x>>a[i].y;
}
if(dfs(0,0))
{
for(int i = 1;i <= n;i++)
{
if(vis[i])
{
q.push_back(i);
}
}
cout<<q.size()<<endl;
for(int i = 0;i < q.size();i++)
{
cout<<q[i]<<" ";
}
cout<<endl;
}
else
{
cout<<-1<<endl;
}
}
return 0;
}