两种dp状态的设置法
比较坑的一个地方:不论是哪种设置法,最后都要特判一下所有骨牌相同的情况,这种情况要把最后的结果/2
因为此时每种骨牌排列,都可以将每块骨牌逆过来,还是合法的,基于我们设置的状态,这样就多统计了一倍,所以要/2
只要有一块骨牌和其他不同,上述情况就不成立
此外:当s[i]==t[i]时,我们只挑选一个计算贡献即可
1.dp[S][i]:当前状态集合为S,末尾是i
/* dp[01][1]=1 dp[01][2]=1 dp[10][1]=1 dp[10][2]=1 dp[11][1]=1 dp[11][2]=1 */ #include<bits/stdc++.h> using namespace std; #define ll long long #define mod 1000000007 ll dp[1<<17][17],s[20],t[20],n; int main(){ int T;cin>>T; while(T--){ cin>>n; int flag=0; for(int i=0;i<n;i++){ cin>>s[i]>>t[i]; if(!(s[i]==s[0] && t[i]==t[0] || s[i]==t[0] && t[i]==s[0])) flag=1; } if(!flag){ ll ans=1; for(int i=1;i<=n;i++) ans=ans*i%mod; cout<<ans<<' ';continue; } memset(dp,0,sizeof dp); dp[0][0]=1; for(int S=0;S<(1<<n);S++){//当前状态是S for(int i=0;i<n;i++)if(!(S>>i & 1)){ //把第i块放在最后的方案数 if(S==0){ dp[S|(1<<i)][s[i]]=(dp[S|(1<<i)][s[i]]+dp[S][0])%mod; if(s[i]!=t[i]) dp[S|(1<<i)][t[i]]=(dp[S|(1<<i)][t[i]]+dp[S][0])%mod; } else { dp[S|(1<<i)][s[i]]=(dp[S|(1<<i)][s[i]]+dp[S][t[i]])%mod; if(s[i]!=t[i]) dp[S|(1<<i)][t[i]]=(dp[S|(1<<i)][t[i]]+dp[S][s[i]])%mod; } } } long long ans=0; for(int i=1;i<=6;i++) ans=(ans+dp[(1<<n)-1][i])%mod; cout<<ans<<' '; } }
2.dp[S][i][0|1] 状态集合S,最后一个是骨牌i,0|1正放,逆放
#include<bits/stdc++.h> using namespace std; #define ll long long #define mod 1000000007 ll dp[1<<17][17][2],s[20],t[20],n; int main(){ int T;cin>>T; while(T--){ cin>>n; int flag=0; for(int i=0;i<n;i++){ cin>>s[i]>>t[i]; if(!(s[i]==s[0] && t[i]==t[0] || s[i]==t[0] && t[i]==s[0])) flag=1; } if(!flag){ ll ans=1; for(int i=1;i<=n;i++) ans=ans*i%mod; cout<<ans<<' ';continue; } memset(dp,0,sizeof dp); dp[0][0][0]=1; for(int S=0;S<(1<<n);S++){//当前状态是S if(S==0){ for(int i=0;i<n;i++){ dp[S|(1<<i)][i][0]=(dp[S|(1<<i)][i][0]+1)%mod; dp[S|(1<<i)][i][1]=(dp[S|(1<<i)][i][1]+1)%mod; } continue; } for(int i=0;i<n;i++)if(S>>i & 1){//最后一块是i for(int j=0;j<n;j++)if(!(S>>j & 1)){ if(s[j]==t[i]) dp[S|(1<<j)][j][0]=(dp[S|(1<<j)][j][0]+dp[S][i][0])%mod; if(s[j]==s[i] && s[i]!=t[i]) dp[S|(1<<j)][j][0]=(dp[S|(1<<j)][j][0]+dp[S][i][1])%mod; if(t[j]==t[i]) dp[S|(1<<j)][j][1]=(dp[S|(1<<j)][j][1]+dp[S][i][0])%mod; if(t[j]==s[i] && s[i]!=t[i]) dp[S|(1<<j)][j][1]=(dp[S|(1<<j)][j][1]+dp[S][i][1])%mod; } } } long long ans=0; for(int i=0;i<n;i++){ ans=(ans+dp[(1<<n)-1][i][0])%mod; if(s[i]!=t[i]) ans=(ans+dp[(1<<n)-1][i][1])%mod; } cout<<ans<<' '; } }