交通灯 并查集
Posted bxd123
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了交通灯 并查集相关的知识,希望对你有一定的参考价值。
Problem Description
相信交通灯对于你来说并不陌生,交通灯分为红色和绿色两个阶段,这两个阶段互相更替,保障着道路的安全。
在杭州一共有n个路口,编号依次为1到n。这些路口之间连接着m条双向道路,每条道路连接着两个不同的路口,且任意两个路口之间最多连接着一条道路。每条道路中央都设置着一个交通灯。
为了保障道路的安全,对于任意两条道路,如果它们连接了同一个路口,那么它们不能同色。
你的朋友正乘着飞机从杭州的上空飞过,并拍了一张杭州的照片。在照片里,每条道路的交通灯的颜色都清晰可辨。
你并不知道你的朋友是在什么时候按下的快门,于是你想统计出有多少种可能的方案。每个方案可以用一个颜色序列col1,col2,…,colm(coli∈{′Red′,′Green′})来描述,表示每个交通灯的颜色。
在杭州一共有n个路口,编号依次为1到n。这些路口之间连接着m条双向道路,每条道路连接着两个不同的路口,且任意两个路口之间最多连接着一条道路。每条道路中央都设置着一个交通灯。
为了保障道路的安全,对于任意两条道路,如果它们连接了同一个路口,那么它们不能同色。
你的朋友正乘着飞机从杭州的上空飞过,并拍了一张杭州的照片。在照片里,每条道路的交通灯的颜色都清晰可辨。
你并不知道你的朋友是在什么时候按下的快门,于是你想统计出有多少种可能的方案。每个方案可以用一个颜色序列col1,col2,…,colm(coli∈{′Red′,′Green′})来描述,表示每个交通灯的颜色。
Input
第一行包含一个正整数T(1≤T≤5000),表示测试数据的组数。
每组数据第一行包含两个正整数n,m(1≤n,m≤100000),表示路口和道路的数量。
接下来m行,每行包含两个正整数ui,vi(1≤ui,vi≤n,ui≠vi),表示一条连接ui路口和vi路口的道路,任意两个路口之间最多连接着一条道路。
输入数据保证所有数据中n和m的总和都不超过1000000。
每组数据第一行包含两个正整数n,m(1≤n,m≤100000),表示路口和道路的数量。
接下来m行,每行包含两个正整数ui,vi(1≤ui,vi≤n,ui≠vi),表示一条连接ui路口和vi路口的道路,任意两个路口之间最多连接着一条道路。
输入数据保证所有数据中n和m的总和都不超过1000000。
Output
对于每组数据输出一行一个整数,即ans,即可能的方案数对1000000007=109+7取模的结果。
注意城市布局可能不能保障道路的安全,此时的答案应该为0。
注意城市布局可能不能保障道路的安全,此时的答案应该为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; }
模拟输入路径写法:
#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; }
以上是关于交通灯 并查集的主要内容,如果未能解决你的问题,请参考以下文章