zoukankan      html  css  js  c++  java
  • 交通灯 并查集

      

    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
  • 相关阅读:
    棋盘完美覆盖数(小规模原理实现)
    Codeforces 115A Party (并查集思维)
    datetime日期和时间
    range与enumerate的区别
    爬取爱套图网上的图片
    python爬取365好书中小说
    列表和元组的方法
    字符串中的方法
    从电源问题出发,带你揭秘新体系结构范式 COA
    KubeCon 2020 演讲集锦|《阿里巴巴云原生技术与实践 13 讲》开放下载
  • 原文地址:https://www.cnblogs.com/bxd123/p/10658413.html
Copyright © 2011-2022 走看看