【叶节点记忆式/深搜式DFS_路径搜索问题】滑动解锁

作为一个爱逛知乎的好少年,小Hi已经知道一共有389112种不同的解锁方案。不过小Hi不满足于此,他希望知道,当已经瞥视到一部分折线的情况下,有多少种不同的方案。

遗憾的是,小Hi看到的部分折线既不一定是连续的,也不知道方向。例如看到1-2-3和4-5-6,那么1->2->3->4->5->6,1->2->3->6->5->4, 3->2->1->6->5->4->8->9等都是合法的方案。

输入

第一行包含一个整数T(1 <= T <= 10),代表测试数据组数。

每个测试数据第一行是一个整数N(0 <= N <= 8),代表小Hi看到的折线段数目。

以下N行每行包含两个整数X, Y (1 <= X, Y <= 9),代表小Hi看到点X和点Y是直接相连的。

输出

对于每组数据输出合法的方案数目。


显然,一个solution就是搜索树上的一个路径。

该路径不停加深,直到延伸到叶节点,然后记录路径(solution),并返回(注意叶节点已经做了该做的处理即记录了答案,返回空就行)。

典型的深搜式DFS:

#include <iostream>
#include <vector>
#include <string.h>
using namespace std;
#define abs(a) (a<0?0-(a):a)
int tt[9][9];

// cached tt[a][b]
int get(int a,int b){
	if(tt[a][b]!=-1) return tt[a][b];
	int s=abs(a-b);
	//// if a->b is a horse-path
	// if(abs(a%3-b%3)==2&&abs(a/3-b/3)==1||
	// abs(a/3-b/3)==1&&abs(a%3-b%3)==2)
	// return -2;//a->b is impossible
	int t=0;
	if(a%3==b%3) {
		if(s<6) t=-2;
		else t=(a+b)/2;
	}
	else if(a/3==b/3){
		if(s<2) t=-2;
		else t=(a+b)/2;
	}
	else{
		int x=min(a,b),y=max(a,b);//@error: x=max(a,b),y=min(a,b)
		if(x==2&&y==6||x==0&&y==8) t=(x+y)/2;
		else t=-2;
	}
	return tt[a][b]=t;
}
void init(){
	memset(tt,-1,sizeof(tt));
	for(int i=0;i<9;i++)
	for(int j=0;j<9;j++)
		get(i,j);
}
void dfs(int &cnt,int curCnt,vector<int> &path,bool map[][9],bool visit[],int depth,int idx){
	if(curCnt==0){
		//four points at least
		if(depth>=4) cnt++;//a solution
	}
	if(depth==9){
		//// debug
		// if(curCnt==0){
			// for(int i=0;i<9;i++){
				// cout<<path[i]+1<<" ";
			// }cout<<endl;
		// }
		return;
	}

	for(int j=0;j<9;j++){
		if(visit[j]) continue;

		int tmp=-1;
		int preCnt=curCnt;
		if(idx>=0){
			tmp=get(idx,j);
			if(tmp>=0){
				if(!visit[tmp]) continue;//tmp not passed yet
			}
			if(map[idx][j]) curCnt--;
		}
		visit[j]=true;
		path.push_back(j);

		dfs(cnt,curCnt,path,map,visit,depth+1,j);

		path.pop_back();
		curCnt=preCnt; 
		visit[j]=false;
	}
}
int main(){
	int casen;cin>>casen;
	bool map[9][9];bool visit[9];
	init();
	for(int casei=0;casei<casen;casei++){
		memset(map,0,sizeof(map));
		memset(visit,0,sizeof(visit));
		int edgen;cin>>edgen;
		for(int i=0;i<edgen;i++){
			int a,b;cin>>a>>b;a--,b--;
			map[a][b]=map[b][a]=true;
		}
		int cnt=0;
		vector<int> path;
		dfs(cnt,edgen,path,map,visit,0,-1);
		cout<<cnt<<endl;
	}
}

考虑另外改变一个条件,如果允许看到的路径<123>可以等价于从1直接到3。则解法会变的更多。

你可能感兴趣的:(【叶节点记忆式/深搜式DFS_路径搜索问题】滑动解锁)