ACM Battle(巧妙暴力)

古往今来的各种传说中存在着很多魔法阵,它们的激活方式也各不相同。传说在北师大电子楼前的小花园里就有一个魔法阵,上次出现还是在很多很多很多年前,但是现在它又出现了!
这时,小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");
        }
    }
}


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值