传送门:http://codeforces.com/problemset/problem/445/B

参考:https://blog.csdn.net/littlewhite520/article/details/77018559

题意:

  有N种药剂编号 1 ~ N,然后有M种反应关系,这里有一个试管,开始时危险系数为 1,每当放入的药剂和瓶子里面的药剂发生反应时危险系数会乘以2,(注意,不管会发生反映的有几组,只要在同一次加入的,只乘一个2;)否则就不变,给出N个药剂和M种反应关系,求最大的危险系数。

思路:这个思路是真的优秀,感觉是一种逆向思维:

  我们假设 1 ~ N 有 M 种反应关系 ,如果有反应关系的我们可以把他们看成是一个集合 ,假设这M种反应构成了 T个集合,那么把这T个集合中的元素依次放入试管,有几个不发生反应呢?当然是T个了,把每个集合看成是一课树,根节点和其子节点反应,这个子节点又和它的子节点发生反应、想一想是一个链状的结构、、、假设每个集合放入时先放根节点(第一个节点),那么每个根节点是不是都不和当前试管中的药剂发生反应呢,因为根节点只和它的子节点发生发应,而他的子节点尚未放入、、所以把这些药剂全部放入,最少只需要 T 个不发生发应。

  至于找集合的个数,可以用并查集或者dfs;

dfs的:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define pb push_back
typedef long long ll;
using namespace std;
const int maxn =  55;

vector<int>mp[maxn];
int vis[maxn];
void dfs(int v)
{
    vis[v] = 1;
    for(int i=0;i<mp[v].size();i++)
    {
        int tmp = mp[v][i];
        if(vis[tmp]==0)
        {
            dfs(tmp);
        }
    }
    return ;
}

int  main(){
    int n,m;
    scanf("%d%d",&n,&m);
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=m;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        mp[a].pb(b);
        mp[b].pb(a);
    }
    ll ans = 1;
    int t = 0;
    for(int i=1;i<=n;i++)
    {
        if(vis[i]==0)
        {   
            dfs(i);
            t++;
        }
    }
    t = n - t;
    for(int i=1;i<=t;i++)
    {
        ans*=2;
    }
    printf("%lld\n",ans);
    return 0;
}
View Code

相关文章:

  • 2022-12-23
  • 2021-11-04
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-10-18
  • 2021-07-12
  • 2022-12-23
猜你喜欢
  • 2021-08-24
  • 2022-03-04
  • 2022-12-23
  • 2022-12-23
  • 2021-07-04
  • 2022-02-17
  • 2022-12-23
相关资源
相似解决方案