题目
n(2<=n<=2e3)个点的图,m(m<=2*n)条无向边
除了1号点度数无限制以外,别的点恰有两条边与之相连,
无自环,可能有重边
红方和蓝方开始都在1号点,所有边都是未被涂色的,
每一次红蓝各选与当前所在节点相邻的一条未被涂色的边,
然后分别将其涂上对应颜色,并走到节点的另一端
如果有一刻二人不能同时选中两条边,游戏结束
问有多少种终局方案,答案对1e9+7取模
两种方案不同当且仅当至少有一条边在出现在planA里没出现在planB里
思路来源
wucstdio代码
题解
首先,这是一个类似花瓣的形状,花瓣中心是1,套着若干个圆环瓣,
先处理出来每个环长,然后考虑做背包,分四种情况
有两种是二人在某个环的中间相遇,分在点上相遇,
和在边上相遇(由于中间只有一条边,无法满足同时选中两条边的要求)
另两种是,两人都在一号点,一人在一号点另一人与之隔一条边
dp[i][j][2]表示当前考虑前i个环里,有些环可以不走,红-蓝的边数=j,当前有无相遇的方案数,
第三维用于枚举最后相遇环时满足无后效性,
转移可以忽略这个环,让红走完这个环,让蓝走完这个环
tp[i][j][2]用于处理后两种情况,
tp[i][j][2]表示当前考虑前i个环,所有环都必须完整走完,红-蓝的边数=j时,当前有无相遇的方案数,
转移考虑让红走完,或者让蓝走完,
则最后无相遇是tp[c][0][0]表示在1号点相遇的方案,
而tp[c][0][1]是枚举了最后一个环的位置,这个位置距离1号点恰好一条边之遥
将三者求和即为最终答案
代码
#include<bits/stdc++.h>
using namespace std;
#define pb push_back
const int N=2e3+10,M=4e3,O=2*M+5,mod=1e9+7;
int n,m,a[N],c,u,v;
vector<int>e[N];
bool vis[N];
int dp[N][O][2],tp[N][O][2],ans;
void add(int &x,int y){
x+=y;
if(x>=mod)x-=mod;
if(x<0)x+=mod;
}
int dfs(int u){
vis[u]=1;
for(int v:e[u]){
if(vis[v])continue;
return dfs(v)+1;
}
return 1;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i){
scanf("%d%d",&u,&v);
e[u].pb(v);e[v].pb(u);
}
vis[1]=1;
for(int v:e[1]){
if(!vis[v]){
a[++c]=dfs(v)+1;
}
}
dp[0][M][0]=tp[0][M][0]=1;
int sz=0;
for(int i=1;i<=c;++i){
for(int j=-sz;j<=sz;++j){
add(dp[i][j+a[i]+M][0],dp[i-1][j+M][0]);//红
add(dp[i][j-a[i]+M][0],dp[i-1][j+M][0]);//蓝
add(dp[i][j+M][0],dp[i-1][j+M][0]);//不
add(dp[i][j+a[i]+M][1],dp[i-1][j+M][1]);//红
add(dp[i][j-a[i]+M][1],dp[i-1][j+M][1]);//蓝
add(dp[i][j+M][1],dp[i-1][j+M][1]);//不
add(tp[i][j+a[i]+M][0],tp[i-1][j+M][0]);//红
add(tp[i][j-a[i]+M][0],tp[i-1][j+M][0]);//蓝
add(tp[i][j+a[i]+M][1],tp[i-1][j+M][1]);//红
add(tp[i][j-a[i]+M][1],tp[i-1][j+M][1]);//蓝
for(int x=1;x<a[i];++x){//红x蓝y
int y=a[i]-x;
add(dp[i][j+x-y+M][1],2ll*dp[i-1][j+M][0]%mod);//环内点相遇 顺逆
}
for(int x=1;x<a[i]-1;++x){
int y=(a[i]-1)-x;
add(dp[i][j+x-y+M][1],2ll*dp[i-1][j+M][0]%mod);//环内边相遇 顺逆
}
add(tp[i][j+(a[i]-1)+M][1],2ll*tp[i-1][j+M][0]%mod);//红 1号点和边相遇 顺逆
add(tp[i][j-(a[i]-1)+M][1],2ll*tp[i-1][j+M][0]%mod);//蓝 1号点和边相遇 顺逆
}
sz+=a[i];
}
add(ans,dp[c][M][1]);
add(ans,tp[c][M][0]);
add(ans,tp[c][M][1]);
printf("%d\n",ans);
return 0;
}