交通灯 并查集

Posted bxd123

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了交通灯 并查集相关的知识,希望对你有一定的参考价值。

  

Problem Description

相信交通灯对于你来说并不陌生,交通灯分为红色和绿色两个阶段,这两个阶段互相更替,保障着道路的安全。

在杭州一共有n个路口,编号依次为1n。这些路口之间连接着m条双向道路,每条道路连接着两个不同的路口,且任意两个路口之间最多连接着一条道路。每条道路中央都设置着一个交通灯。

为了保障道路的安全,对于任意两条道路,如果它们连接了同一个路口,那么它们不能同色。

你的朋友正乘着飞机从杭州的上空飞过,并拍了一张杭州的照片。在照片里,每条道路的交通灯的颜色都清晰可辨。

你并不知道你的朋友是在什么时候按下的快门,于是你想统计出有多少种可能的方案。每个方案可以用一个颜色序列col1,col2,,colm(coli{Red,Green})来描述,表示每个交通灯的颜色。

Input

第一行包含一个正整数T(1T5000),表示测试数据的组数。

每组数据第一行包含两个正整数n,m(1n,m100000),表示路口和道路的数量。

接下来m行,每行包含两个正整数ui,vi(1ui,vin,uivi),表示一条连接ui路口和vi路口的道路,任意两个路口之间最多连接着一条道路。

输入数据保证所有数据中nm的总和都不超过1000000

Output

对于每组数据输出一行一个整数,即ans,即可能的方案数对1000000007=109+7取模的结果。

注意城市布局可能不能保障道路的安全,此时的答案应该为0

Sample Input

2
3 3
1 2
2 3
3 1
4 2
1 2
3 4

Sample Output

0
4

比赛的时候拿到这题感觉是可以做的
一开始想到 最大匹配 但是好像不行
然后开并查集 要求求出联通块个数cnt 然后2的cnt次幂就是答案( 比赛的时候居然写成2*cnt了 不知道错到哪里去了QAQ )
题意还要求我们判环
如果是奇数环则不行 偶数环是可以的 如正方形和三角形

比赛的时候我在并查集里面加了cnt 以此来判环
这种想法是对的 因为一个点如果有三条边显然是错的 除去这种情况 剩下的就是一个点小于等于两条边 那么只能构成一条链或者一个环 比赛的时候几乎写出来了 但是最后答案的形式弄错饿了(2*cnt)

其实很多情况不需要什么算法 直接乱搞就行了
补题的时候很快就想到思路 用一个vis就可以表示两种灯的状态了

过程中还是wa了一些细节
1.爆int了 开ll 并且只要是乘法 只管加mod就行了!!!
2.如果是0个联通块 不应该是2的0次方 而是0

一定要等思路完善了再开始敲 不然只是浪费时间 并且只想沿着错误的思路思考 难以放弃并且重新开启新的思路


比赛的思路:
技术图片
#include<bits/stdc++.h>
using namespace std;
//input
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);i--)
#define RI(n) scanf("%d",&(n))
#define RII(n,m) scanf("%d%d",&n,&m);
#define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define RS(s) scanf("%s",s);
#define ll long long
#define inf 0x3f3f3f3f
#define REP(i,N)  for(int i=0;i<(N);i++)
#define CLR(A,v)  memset(A,v,sizeof A)
//////////////////////////////////
#define N 500+5
#define mod 1000000007
int vis[100005];
int cnt[100005];
int f[100005];
int find1(int x)
{
    return x==f[x]?x:f[x]=find1(f[x]);
}
void union1(int a,int b)
{
    int x=find1(a);
    int y=find1(b);
    if(x!=y)
    f[x]=y,cnt[y]+=cnt[x];
}
ll fastpow(ll x,int n)
{
    ll ans=1;
    while(n)
    {
        if(n&1)
            ans*=x,ans%=mod;
        x*=x,x%=mod;//疯狂加mod就完事了
     n>>=1;
    }
    return ans%mod;
}
int main()
{
    int cas;
    RI(cas);
    while(cas--)
    {
        int n,m;RII(n,m);
        rep(i,1,n)
        f[i]=i,vis[i]=0,cnt[i]=1;
        int ok=1;
        while(m--)
        {
            int a,b;RII(a,b);
            if(!ok)continue;
            vis[a]++;
            vis[b]++;
            if(vis[a]>2||vis[b]>2)ok=0;
            int x=find1(a),y=find1(b);
            if(x!=y)
                union1(a,b);
            else
            {
                if(cnt[x]%2==1)ok=0;//如果为奇数环 则无法实现
                else
                union1(a,b);
            }
        }
        if(!ok)printf("0
");
        else
        {
            ll cnt=0;
            rep(i,1,n)
            if(f[i]==i&&vis[i])
            cnt++;
            if(cnt==0)printf("0
");
            else printf("%lld
",fastpow(2,cnt));
        }
    }
    return 0;
}
View Code

 


模拟输入路径写法:
技术图片
#include<bits/stdc++.h>
using namespace std;
//input
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);i--)
#define RI(n) scanf("%d",&(n))
#define RII(n,m) scanf("%d%d",&n,&m);
#define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define RS(s) scanf("%s",s);
#define ll long long
#define inf 0x3f3f3f3f
#define REP(i,N)  for(int i=0;i<(N);i++)
#define CLR(A,v)  memset(A,v,sizeof A)
//////////////////////////////////
#define N 500+5
#define mod 1000000007
int vis[100005][2];
int f[100005];
int find1(int x)
{
    return x==f[x]?x:f[x]=find1(f[x]);
}
ll fastpow(ll x,int n)
{
    ll ans=1;
    while(n)
    {
        if(n&1)
            ans*=x,ans%=mod;
        x*=x,x%=mod;//疯狂加mod就完事了
     n>>=1;
    }
    return ans%mod;
}
int main()
{
    int cas;
    RI(cas);
    while(cas--)
    {
        int n,m;
        RII(n,m);
        rep(i,1,n)f[i]=i,vis[i][0]=vis[i][1]=0;
        int ok=1;
        while(m--)
        {
            int a,b;
            RII(a,b);
            if(!ok)continue;
            if(!vis[a][0]&&!vis[b][0])
                vis[a][0]=vis[b][0]=1,f[ find1(a) ]=find1(b);
            else if(!vis[a][1]&&!vis[b][1])
                vis[a][1]=vis[b][1]=1,f[ find1(a) ]=find1(b);
            else
                ok=0;
        }
        if(!ok)printf("0
");
        else
        {
            ll cnt=0;
            rep(i,1,n)
            if(f[i]==i&&( vis[i][0]||vis[i][1]) )//如果是孤立的点而不是路则不能给路染色
                cnt++;

            if(cnt==0)
                printf("0
");
            else
            printf("%lld
",fastpow( 2,cnt ));
        }
    }
    return 0;
}
View Code

以上是关于交通灯 并查集的主要内容,如果未能解决你的问题,请参考以下文章

CSP 201703-4 地铁修建最小生成树+并查集

并查集通畅工程(航电1232)

CSP 地铁修建 Kruskal (最小生成树+并查集)

并查集--畅通工程

图论——并查集

畅通工程(并查集)