我的思路:
dp[s][i] s集合里最小的点到其他点的路径数;
dp[s][i] += dp[s^(1<<i)]j
ans加上可以构成环的路径数.怎么才能构成环呢? 如a->b->…->c ,如果知道ac是可达的,只要加上a,经过ab…到达c的路径数就可以了。注意a是这个集合里最小的数。而且同一个环会被记录两次,因为2条路径才是一个环。
#include<bits/stdc++.h>
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define IL inline
#define ls (t<<1)
#define rs (t<<1|1)
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
IL LL read()
{
LL x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
#define io read()
const int mod=1e9+7,ni=5e8+4;
IL void add_ans(int &x,int y)
{
x+=y;
if(x>=mod) x-=mod;
}
const int N=100028;
int n,m;
int x,y;
int nume,head[N];
struct edge{
int to,nxt;
}e[N*2];
IL void add_edge(int x,int y)
{
e[++nume]=(edge){y,head[x]};head[x]=nume;
}
namespace sub1{
const int N=20;
int f[(1<<N)+8][N];
int ans;
IL int lowbit(const int &x)
{
return x&-x;
}
IL void solve()
{
for(int i=1;i<=n;++i){
f[1<<(i-1)][i]=1;
}
int ms=1<<n;
for(int s=1;s<ms;++s){
for(int i=1;i<=n;++i){
if(f[s][i]>0){
for(int j=head[i];j;j=e[j].nxt){
int to=e[j].to;
if(lowbit(s)>(1<<(to-1))){
continue;
}
if((s>>(to-1))&1){
if(lowbit(s)==(1<<(to-1))){
//ans+=f[s][i];
add_ans(ans,f[s][i]);
}
}
else{
//f[s|(1<<(to-1))][to]+=f[s][i];
add_ans(f[s|(1<<(to-1))][to],f[s][i]);
}
}
}
}
}
ans=1ll*(ans-m+mod)*ni%mod;
printf("%d",ans);
}
}
int main()
{
n=io;m=io;
for(int i=1;i<=m;++i){
x=io;y=io;
add_edge(x,y);
add_edge(y,x);
}
if(n<=20){
sub1::solve();
return 0;
}
if(m==n-1){
printf("%d",0);
return 0;
}
if(m==n){
printf("%d",1);
return 0;
}
printf("%d",m-n+1+rand()%(m-n+1));
return 0;
}
考虑⽣成树,注意到⼀个环⼀定是若⼲个⾮树边对应的环
异或起来。
所以答案不会超过2^16次。
缩完⼀度点和⼆度点之后爆搜即
#include<bits/stdc++.h>
#define ll long long
#define MAXN 200010
using namespace std;
int n,m,cnt=1,num,sum,M,S,top,ans;
bool is_ok[MAXN],circle[MAXN],vis[MAXN],on[MAXN];
int flag[MAXN],ext[MAXN],head1[MAXN],tot,id[MAXN],fa[MAXN][20],dep[MAXN],in[MAXN],now[MAXN],fat[MAXN],st[MAXN],head[MAXN],head2[MAXN];
bool cmp(int i,int j) {return id[i]<id[j];}
struct Edge
{
int u,v;
}e1[MAXN<<1],e2[MAXN<<1];
struct MAXNode{
int nxt,to;
}e[MAXN<<1],E[MAXN<<1];
void Add(int u,int v) {fat[v]=u;}
void add(int from,int too) {e[++cnt].nxt=head1[from];head1[from]=cnt;e[cnt].to=too;}
void Add_edge(int u,int v) {add(u,v);add(v,u);}
void add1(int from,int too) {E[++num].nxt=head2[from];head2[from]=num;E[num].to=too;}
int Add_edge1(int u,int v)
{
in[u]++;in[v]++;
if(flag[u]!=sum) head2[u]=0,flag[u]=sum;
if(flag[v]!=sum) head2[v]=0,flag[v]=sum;
add1(u,v);add1(v,u);return 0;
}
int doit(int i)
{
e2[++M].u=e1[i].u,e2[M].v=e1[i].v;
if(!on[e1[i].u]) on[e1[i].u]=1,now[++S]=e1[i].u;
if(!on[e1[i].v]) on[e1[i].v]=1,now[++S]=e1[i].v;return 0;
}
void dfs(int x)
{
vis[x]=1;id[x]=++tot;
for(int i=head1[x];i;i=e[i].nxt) {
int y=e[i].to;if(vis[y]) continue;
fa[y][0]=x;dep[y]=dep[x]+1;dfs(y);is_ok[i>>1]=1;
}
}
void df1(int x)
{
if(ext[x]==sum) return;ext[x]=sum;
for(int i=head2[x];i;i=E[i].nxt) {
int y=E[i].to;df1(y);
}
}
void build_st()
{
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);
int t=dep[u]-dep[v];
for(int i=0;i<=19;i++)
if(t & (1<<i))
u=fa[u][i];
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];
}
void work()
{
for(int s=1;s<(1<<M);s++) {
for(int i=1;i<=S;i++) circle[now[i]]=0,in[now[i]]=0;
num=0;sum++;
for(int i=1;i<=M;i++)
if((s>>(i-1)) & 1) {
for(int j=e2[i].u;j;j=fat[j]) circle[j]^=1;
for(int j=e2[i].v;j;j=fat[j]) circle[j]^=1;
}
for(int i=1;i<=M;(s & (1<<(i-1)))?Add_edge1(e2[i].u,e2[i].v):0,i++);
for(int i=1;i<=S;(circle[now[i]] && fat[now[i]])?Add_edge1(now[i],fat[now[i]]):0,i++);
bool ok=1;
for(int i=1;i<=S;i++) {if(in[now[i]] && in[now[i]]!=2) ok=0;if(!ok) break;}
if(ok) for(int i=1;i<=S;i++) if(in[now[i]]) {df1(now[i]);break;}
if(ok) for(int i=1;i<=S && ok;(in[now[i]] && ext[now[i]]!=sum)? ok=0,0:0,i++);
ans+=ok;
}
}
void insert()
{
int pos=S;
for(int i=1;i<=S;i++) {
int x=now[i];
if(!top) {st[++top]=x;continue;}
int LCA=lca(st[top],x);
while(dep[st[top-1]]>dep[LCA] && top>1) {Add(st[top-1],st[top]);top--;}
if(dep[LCA]<dep[st[top]]) {Add(LCA,st[top]);top--;}
if(!top || dep[st[top]]<dep[LCA]) st[++top]=LCA;
st[++top]=x;
if(!on[LCA]) {on[LCA]=1;now[++pos]=LCA;}
}
while(top>1) {Add(st[top-1],st[top]);top--;}
S=pos;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;scanf("%d%d",&e1[i].u,&e1[i].v),Add_edge(e1[i].u,e1[i].v),i++);
dfs(1);build_st();
for(int i=1;i<=m;is_ok[i]?0:doit(i),i++);
sort(now+1,now+S+1,cmp);insert(); work();printf("%d",ans);
return 0;
}