CodeForces - 445B - DZY Loves Chemistry-转化问题

传送门: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

 

并查集:

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

const int maxn = 55;
int n,m;
int fa[maxn];
void init(){
    for(int i=1;i<=n;i++)
        fa[i]=i;
}
int finx(int x)
{
    if(fa[x]==x)return x;
    else return fa[x] = finx(fa[x]);
}
void uni(int x,int y)
{
    int px = finx(x);
    int py = finx(y);
    if(px==py)return ;
    else fa[px] = py;
}
int main(){
    scanf("%d%d",&n,&m);
    init();
    for(int i=1;i<=m;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        uni(a,b);
    }
    int t=0;
    for(int i=1;i<=n;i++)
        if(fa[i]==i)t++;
    t = n - t;
    long long ans = 1;
    for(int i=1;i<=t;i++)
    {
        ans *= 2;
    }
    printf("%lld\n",ans);
    return 0;
}
View Code

 

posted @ 2018-04-04 23:45  ckxkexing  阅读(135)  评论(0编辑  收藏  举报