zoj 1008 DFS+剪枝(小坑爹的剪枝)
/* 题意:给出一个矩形由n*n个小矩形,每个小矩形由四个三角形组成,分别在上下左右,每个三角形有一个数 字,通过调换这些矩形的位置,找出一种情况能使得任意两个相邻的小矩形之间有公共边的两个三角形的值 一样,能找出这张情况则输出possible,否则输出impossible。 题解:DFS,搜索剪枝; n*n个位置分别对应填入n*n个矩形,从左往右,自上而下的顺序依次搜索,对应每个位置都遍历一遍所有的 矩形,并且记录该矩形的值。 注意:测试数据包含有重复的矩形,因此在搜索的时候如果没有处理重复的矩形,则会出现一种情况:遍历 的两种摆法中两个相同的矩形分别在两个位置,会因为没有处理重复而通过颠倒两个矩形的出现顺序来重新 搜索一遍,实际上是一样的,这里的剪枝很重要,否则会超时,估计数据有很多重复的矩形。 */ #include <cstdio> #include <cstring> #include <algorithm> using namespace std; struct square { int top,right,bottom,left; }s[50];//记录矩形 int n,q;//n记录大矩形的边,q记录矩形的种类数 int vis[50];//记录第i种矩形由多少个 int m[50];//记录n*n个位置中对应的矩形的种类 bool flag;//记录是否能找到相邻状态 void dfs(int pos)//pos指当前在位置 { if (pos == n*n)//搜索到n*n使表示所有的位置都已经填满 { flag = true; return ; } if (flag) return ; for(int i=0; i<q; i++) {//遍历所有存在的小矩形填入当前的pos位置中 if (vis[i]) { if (pos==0)//位于第一个位置,则只需直接填入矩形i { vis[i]--;//第i种矩形数目减一 m[pos] = i;//记录当前pos位置填入的矩形种类为i dfs(pos+1);//搜索下一个位置 vis[i]++; } else if (pos < n)//当前位置位于第一行 { if (s[m[pos-1]].right == s[i].left)//判断与左边是否能相邻(pos-1表示当前位置的左边) { vis[i]--; m[pos] = i; dfs(pos+1); vis[i]++; } } else if (pos % n == 0)//位于最左列,左边没有位置 { if (s[m[pos-n]].bottom == s[i].top)//判断与上方的矩形是否能相邻(pos-n表示当前位置的上方) { vis[i]--; m[pos] = i; dfs(pos+1); vis[i]++; } } else {//其余的情况都判断是否能与上方和左边的矩形相邻 if (s[m[pos-1]].right==s[i].left && s[m[pos-n]].bottom==s[i].top) { vis[i]--; m[pos] = i; dfs(pos+1); vis[i]++; } } if (flag) return ; } } } int main(void) { int cas=1,a,b,c,d; while (~scanf("%d",&n) && n) { memset(vis,0,sizeof(vis)); q = 0; for(int i=0; i<n*n; i++) { scanf("%d%d%d%d",&a,&b,&c,&d); int j; for(j=0; j<q; j++) { if (s[j].top==a && s[j].right==b && s[j].bottom==c && s[j].left==d) { vis[j]++; break; } } if (j == q) { s[q].top = a; s[q].right = b; s[q].bottom = c; s[q].left = d; vis[q]++; q++; } } flag = false; memset(m,0,sizeof(m)); dfs(0); if (cas != 1) printf("\n"); if (flag) printf("Game %d: Possible\n",cas); else printf("Game %d: Impossible\n",cas); cas++; } return 0; }