古往今来的各种传说中存在着很多魔法阵,它们的激活方式也各不相同。传说在北师大电子楼前的小花园里就有一个魔法阵,上次出现还是在很多很多很多年前,但是现在它又出现了!
这时,小Q同学面无表情地说:“传说这个魔法阵都会在都会在来自远古的恶魔Awesome Crystal Monster(ACM)降临的时候出现,现在,这个时候终于要到来了吗!”话音未落,小Q同学已经走到了魔法阵前,取出一个小瓶,开始用瓶中的圣水激活这个魔法阵,“你们快退后,这里就交给我了!”
这时,小Q同学面无表情地说:“传说这个魔法阵都会在都会在来自远古的恶魔Awesome Crystal Monster(ACM)降临的时候出现,现在,这个时候终于要到来了吗!”话音未落,小Q同学已经走到了魔法阵前,取出一个小瓶,开始用瓶中的圣水激活这个魔法阵,“你们快退后,这里就交给我了!”
这个魔法阵由一些点和一些连接这些点的边构成,当小Q同学把圣水滴在一个点上时,和这个点相连的所有边就会被点亮并发出神圣的光芒,当魔法阵所有的边都点亮的时候,就会出现强大的神圣力量。但是小Q同学拥有的圣水非常有限,只有10滴,现在小Q同学想知道他最少可以用多少滴圣水点亮整个魔法阵,如果耗尽圣水也不能点亮,就只能打出一波GG了。
输入描述:
第一行包含一个正整数T(≤ 20),表示测试数据的组数, 对于每组测试数据, 第一行是两个整数n(1 ≤ n ≤ 1000)和m(1 ≤ m ≤ 2000),表示魔法阵的点数和边数, 接下来m行,每行包含两个整数u,v(1 ≤ u,v ≤ n),表示有一条边连接了u号点和v号点。
输出描述:
对于每组测试数据,如果使用不超过10滴圣水可以点亮整个魔法阵,输出最少需要的圣水滴数,否则输出"GG"(不含引号)。
示例1
输入
2 4 3 1 2 1 3 1 4 4 4 1 2 2 3 3 4 4 1
输出
1 2
说明
对于第一组样例,最优方案是在1号点滴一滴圣水, 对于第二组样例,一个最优方案是在1号点和3号点各滴一滴圣水。
题目思路:
一开始写了一个毫无证明的贪心,顺了wa了,我们从数据来看只有10,所以应该跟暴力有关系,但是怎么去暴力呢,对于这个来说
我们容易想到去枚举点的子集,但是n有1000,那么复杂度有2^1000*m ,显然不行,我们分析可以发现,对于每一条边,他的两个顶点一定是有至少一个被染色了的,所以我们可以去考虑每一条边,对于当前边如果有至少一个顶点被染色,那么就去继续遍历,否则就去回溯哪一个顶点被染色了,如果深度超过10直接就退出,复杂度是2^10*m
这题的关键点就是发现对于一条边来说,肯定要有一个顶点被染色,这样我们就能继而想到枚举边,根据边的情况分析。
ac代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<sstream>
#include<map>
#include<vector>
#include<set>
#define LL long long
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
int T;
int n,m;
struct node
{
int u,v;
}E[2000+5];
int vis[1000+5];
int ans = INF;
void dfs(int sum,int deep)
{
if(deep>10){
return;
}
if(sum==m){
ans = min(deep,ans);
return ;
}
if(vis[E[sum].u]||vis[E[sum].v]){
dfs(sum+1,deep);
}
else{
vis[E[sum].u] = 1;
dfs(sum+1,deep+1);
vis[E[sum].u] = 0;
vis[E[sum].v] = 1;
dfs(sum+1,deep+1);
vis[E[sum].v] = 0;
}
}
int main()
{
scanf("%d",&T);
while(T--){
ans = INF;
scanf("%d%d",&n,&m);
memset(vis,0,sizeof(vis));
for(int i = 0;i<m;i++){
int a,b;
scanf("%d%d",&E[i].u,&E[i].v);
}
dfs(1,0);
if(ans<=10)
cout<<ans<<endl;
else{
puts("GG");
}
}
}