题意:手机滑动解锁,要求长度至少为4 每次可以走到相邻点,每个点只经过一次,给出某个路径的一部分n条边,问该路径有多少合法方案
两个点相邻当且仅当以这两个点为端点的线段上不存在尚未经过的点 4213合法,132非法
首先保存i->j时必须经过中间点,不考虑路径要求的n条边时 容易用dfs算出所有可能路径
由于最终路径要包含所给n条边,则dfs时记录路径中的边,当路径合法时判断是否有所有的n条边即可
#include <bits/stdc++.h>
using namespace std;
const int N=2e2+20;
int vis[N],ans,n;
int mk[N][N];//mk[i][j] i->j中间点
int p[N][N];//记录路径中的边
pair<int,int> a[N];//必须经过的n条边
void dfs(int u,int cnt)//当前点和路径长度
{
if(cnt>=4)
{
bool flag=true;;
for(int i=1;i<=2*n;i+=2)
{
flag=false;
int u=a[i].first,v=a[i].second;
if(p[u][v]||p[v][u])
flag=true;
if(flag==false)
break;
}
if(flag)
ans++;
}
for(int i=1;i<=9;i++)
{
if(vis[i]) continue;
if(vis[mk[u][i]])//从u->i时 中间点必须已经访问
{
vis[i]=1;
p[u][i]=1;//path
dfs(i,cnt+1);
p[u][i]=0;
vis[i]=0;
}
}
}
int main()
{
memset(mk,0,sizeof(mk));
mk[1][3]=mk[3][1]=2;
mk[1][7]=mk[7][1]=4;
mk[4][6]=mk[6][4]=mk[2][8]=mk[8][2]=5;
mk[1][9]=mk[9][1]=mk[3][7]=mk[7][3]=5;
mk[3][9]=mk[9][3]=6;
mk[7][9]=mk[9][7]=8;
int t;
cin>>t;
while(t--)
{
ans=0;
memset(vis,0,sizeof(vis));
vis[0]=1;//无中间点的设为0
cin>>n;
int u,v;
for(int i=1;i<=2*n;i+=2)
{
cin>>u>>v;
a[i].first=u;
a[i].second=v;
a[i+1].first=v;
a[i+1].second=u;
}
for(int i=1;i<=9;i++)
{
vis[i]=1;
dfs(i,1);
vis[i]=0;
}
cout<<ans<<endl;
}
return 0;
}