版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lifelikes/article/details/83217878
题意 给出一个图 ,问其中有多少个简单环。
边数最多比点数多15
解题思路
边数最多比点数多15。 这是一个很经典的条件。 1.想到状压枚举,2.想到建出生成树,然后暴力加边。
思考枚举边的时候如何判断是否有环。
这是一个图论小技巧,将选出来的边的端点 往上异或边异或到根节点, 异或完成后,所有值等于1的边就是应该要选的边。
然后暴力判断这些边是否能构成一个简单环即可。 但这样 复杂度会是O(n*size(E)) 。
然后用虚树优化一下就可以了。 这样 复杂度就很低了。
整个的复杂度就变成了构建虚树的复杂度。 已经非常优秀的算法了。
自己整理了一个虚数的板子 感觉还是很有趣的。
#include <bits/stdc++.h>
#define LL long long
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pb push_back
#define MP make_pair
#define lowbit(x) x&-x
#define clr(a) memset(a,0,sizeof(a))
#define _INF(a) memset(a,0x3f,sizeof(a))
#define FIN freopen("in.txt","r",stdin)
#define IOS ios::sync_with_stdio(false)
#define fuck(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int MAX = 1e5+30;
class Edge {
public:
int u,v,next,w;
};
class GRAPH {
public:
int tot;
int head[MAX];
Edge edge[MAX<<1];
void init() {
memset(head,-1,sizeof head);
tot=0;
}
void add(int u,int v,int w) {
edge[tot].u=u,edge[tot].v=v;
edge[tot].next=head[u];
edge[tot].w=w;
head[u]=tot;
tot++;
}
};
GRAPH t_tree;
int id[MAX];
bool cmp(int &i,int &j) {
return id[i]<id[j];
}
class VTREE {
public:
vector<int> node;
int n;
int root;
GRAPH v_tree;
void init(int _root,int _n,vector<int> &_node) { //树根 原树的大小,关键点
v_tree.init();
root = _root;
n=_n;
node=_node;
}
bool vis[MAX];
int indx;
int fa[MAX][20],dep[MAX];
void dfs(int u) {
vis[u]=1,id[u]=++indx;
for(int i=t_tree.head[u]; i!=-1; i=t_tree.edge[i].next) {
int v= t_tree.edge[i].v;
if(vis[v])
continue;
fa[v][0]=u;
dep[v]=dep[u]+1;
dfs(v);
}
}
void prelca() {
indx=0;
dfs(root);
for(int j = 1; j<20; j++) {
for(int i=1; i<=n; i++) {
fa[i][j]=fa[fa[i][j-1]][j-1];
}
}
}
int lca(int u,int v) {
if(dep[u]<dep[v])
swap(u,v);
for(int k=dep[u]-dep[v],j=0; k; j++,k>>=1) {
if(k&1)
u = fa[u][j];
}
if(u==v)
return u;
for(int j=19; j>=0; j--) {
if(fa[u][j]!=fa[v][j])
u =fa[u][j],v=fa[v][j];
}
return fa[u][0];
}
int top,stk[MAX],key[MAX];
void build() {
prelca();
memset(key,0,sizeof key);
int tops=node.size();
//cout<<"tops:"<<tops<<endl;
sort(node.begin(),node.end(),cmp);
for(int i=0; i<tops; i++) {
key[node[i]]=1;
}
for(int i=0; i<tops; i++) {
//cout<<node[i]<<"<,>id:"<<id[node[i]]<<endl;
int x = node[i];
if(!top) {
stk[++top] = x;
continue;
}
int plca = lca(stk[top],x);
while(dep[stk[top-1]]>dep[plca] && top>1) {
v_tree.add(stk[top-1],stk[top],0);
top--;
}
if(dep[plca]< dep[stk[top]]) {
v_tree.add(plca,stk[top],0);
top--;
}
if(!top || dep[stk[top]]<dep[plca])
stk[++top]=plca;
stk[++top] = x;
if(!key[plca]) {
key[plca]=1;
node.push_back(plca);
}
}
while(top>1) {
if(stk[top-1]!=stk[top])
v_tree.add(stk[top-1],stk[top],0);
top--;
}
}
};
VTREE vtree;
vector<pair<int,int> > nE;
vector<int> nN;
int dsu[MAX];
int finds(int x) {
if(dsu[x]==x)
return x;
return dsu[x]=finds(dsu[x]);
}
int vis[MAX];
int fa[MAX];
void getfa(int u,int pre) {
fa[u]=pre;
for(int i=vtree.v_tree.head[u]; i!=-1; i=vtree.v_tree.edge[i].next) {
int v=vtree.v_tree.edge[i].v;
if(v==pre)
continue;
getfa(v,u);
}
}
void slove(int u,int c) {
while(u!=-1) {
if(vis[u])
vis[u]=0;
else
vis[u]=c;
u=fa[u];
}
}
int checks[MAX];
vector<int> G[MAX];
int num;
int du[MAX];
bool dfs(int u,int pre){
if(checks[u]) return 0;
checks[u]=1;
num++;
for(int i=0;i<G[u].size();i++){
if(G[u][i]==pre) continue;
if(dfs(G[u][i],u)){
continue;
}else{
return 0;
}
}
return 1;
}
int main() {
t_tree.init();
int n,m;
scanf("%d %d",&n,&m);
for(int i=0; i<=n; i++) {
dsu[i]=i;
}
for(int i=0; i<m; i++) {
int u,v;
scanf("%d %d",&u,&v);
int x=finds(u),y=finds(v);
if(x==y) {
nN.push_back(v);
nN.push_back(u);
nE.push_back(make_pair(u,v));
} else {
t_tree.add(u,v,0);
t_tree.add(v,u,0);
dsu[x]=y;
}
}
sort(nN.begin(),nN.end());
nN.push_back(1);
nN.erase(unique(nN.begin(),nN.end()),nN.end());
vtree.init(1,n,nN);
vtree.build();
getfa(1,-1);
int top=(1<<nE.size());
int ans = 0;
vector<int> cnt;
for(int i=1; i<top; i++) {
for(int j=0;j<vtree.node.size();j++){
int v= vtree.node[j];
checks[v]=vis[v]=du[v]=0;
G[v].clear();
}
cnt.clear();
vector<pair<int,int> > P;
vector<int> counts;
for(int j=0; j<nE.size(); j++) {
if((1<<j)&i){
slove(nE[j].first,i);
slove(nE[j].second,i);
G[nE[j].first].push_back(nE[j].second);
G[nE[j].second].push_back(nE[j].first);
du[nE[j].first]++;
du[nE[j].second]++;
P.push_back(make_pair(nE[j].second,nE[j].first));
counts.push_back(nE[j].second);
counts.push_back(nE[j].first);
}
}
for(int j=0;j<vtree.node.size();j++){
int v= vtree.node[j];
if(vis[v]==i){
G[fa[v]].push_back(v);
G[v].push_back(fa[v]);
du[fa[v]]++;
du[v]++;
P.push_back(make_pair(v,fa[v]));
counts.push_back(v);
counts.push_back(fa[v]);
}
}
sort(counts.begin(),counts.end());
counts.erase(unique(counts.begin(),counts.end()),counts.end());
int ok=1;
for(int i=0;i<P.size();i++){
if(du[P[i].first]!=2 || du[P[i].second]!=2){
ok=0;
}
}
num=0;
dfs(P[0].first,-1);
if(num!=counts.size()){
ok=0;
}
if(P.size()==0) ok=0;
if(ok) ans++;
}
cout<<ans<<endl;
return 0;
}
//1 2
//2 4
//4 8
//4 9
//2 5
//5 10
//5 11
//1 3
//3 6
//6 12
//6 13
//3 7
//7 14
//11 12
//5 6