第七屆 藍橋杯 方格填數 dfs
阿新 • • 發佈:2019-03-22
code ret 圖片 藍橋 可能 div include [] names
如下的10個格子
填入0~9的數字。要求:連續的兩個數字不能相鄰。 (左右、上下、對角都算相鄰)
一共有多少種可能的填數方案?
請填寫表示方案數目的整數。
註意:你提交的應該是一個整數,不要填寫任何多余的內容或說明性文字。
方法一:遍歷
#include<iostream> #include<algorithm> #include<cstring> #include<cmath> using namespace std; int map[6][6]; int ans=0; int Abs(int i,int j)//判斷 8個方向{ if(abs(map[i-1][j]-map[i][j])==1) return 0; if(abs(map[i+1][j]-map[i][j])==1) return 0; if(abs(map[i][j+1]-map[i][j])==1) return 0; if(abs(map[i][j-1]-map[i][j])==1) return 0; if(abs(map[i-1][j-1]-map[i][j])==1) return 0; if(abs(map[i+1][j-1]-map[i][j])==1) return 0; if(abs(map[i-1][j+1]-map[i][j])==1) return 0; if(abs(map[i+1][j+1]-map[i][j])==1) return 0; return 1; } int f()//判斷相鄰的數是否連續 { if(Abs(1,3)&&Abs(2,1)&&Abs(2,2)&&Abs(2,3)&&Abs(2,4)&&Abs(3,2)) return 1; return 0; } int main() { memset(map,-2,sizeof(map)); int a[] = {0,1,2,3,4,5,6,7,8,9}; do{ map[1][2]=a[0]; map[1][3]=a[1]; map[1][4]=a[2]; map[2][1]=a[3]; map[2][2]=a[4]; map[2][3]=a[5]; map[2][4]=a[6]; map[3][1]=a[7]; map[3][2]=a[8]; map[3][3]=a[9]; ans+=f(); }while(next_permutation(a,a+10)); cout<<ans<<endl; return 0; }
方法二: dfs
#include <stdio.h> #include <stdlib.h> int ans = 0, flag[10] = {0}; int Check(int a[][4], int x, int y) { static int dx[] = {0, -1, -1, -1}, dy[] = {-1, -1, 0, 1}; for(int i = 0; i < 4; i ++) if( (x + dx[i] >= 0 && x + dx[i] < 3) && (y + dy[i] >= 0 && y + dy[i] < 4) ) { if( 1 == abs(a[x][y] - a[ x + dx[i] ][ y + dy[i] ])) return 0; } return 1; } void dfs(int a[][4], int x, int y) { if(2 == x && 3 == y){ ans ++; return ; } for(int num = 0; num <= 9; num ++) if(!flag[num]){ a[x][y] = num; flag[num] = 1; if(Check(a, x, y)){ if(y + 1 < 4) dfs(a, x, y + 1); else dfs(a, x + 1, 0); } flag[num] = 0; } } int main() { int a[3][4] = {-20}; dfs(a, 0, 1); printf("%d", ans); return 0; }
方法三:
看到這題第一個想到的方法就是回溯,就很像八皇後,能填進去就填,填不進去就看下一個位置(我做的是0---9不重復使用)
我感覺這題麻煩就在判斷上
1.首先要判斷一個點的8個方向相減的絕對值是否為1,為1不能填入,不為1判斷是否使用過這個數,沒使用填入 進行下一個位置
2.如果填入的位置到達最後一列應該換行看下一行的第一個位置進行判斷
3.填到最後每一個情況總sum++就行了
上代碼
#include<iostream> using namespace std; int a[3][4]; int num = 0; int v[10] = {0}; int pd(int k, int i, int j){//這個就是判斷啦。。寫的有點繁瑣 if (i-1>=0 && (a[i - 1][j] == k - 1 || a[i - 1][j] == k + 1) ) return 0; if (j-1>=0 && (a[i][j - 1] == k + 1 || a[i][j - 1] == k - 1) ) return 0; if (i-1>=0 && j-1>=0 && (a[i - 1][j - 1] == k + 1 || a[i - 1][j - 1] == k - 1)) return 0; if (i-1>=0 && j+1<4 && (a[i - 1][j + 1] == k + 1 || a[i - 1][j + 1] == k - 1)) return 0; if (j + 1 < 4 && (a[i][j + 1] == k + 1 || a[i][j + 1] == k - 1)) return 0; if (i + 1 < 3 && (a[i + 1][j] == k + 1 || a[i + 1][j] == k - 1)) return 0; if (i + 1 < 3 && j - 1 >= 0 && (a[i + 1][j - 1] == k + 1 || a[i + 1][j - 1] == k - 1)) return 0; if (i + 1 < 3 && j + 1 < 4 && (a[i + 1][j + 1] == k + 1 || a[i + 1][j + 1] == k - 1)) return 0; return 1; } void f(int i, int j){ if (i == 2&&j==3){//已經填入到最後一個說明這種情況滿足,num++ num++; return; } for (int k = 0; k <= 9; k++){ if (pd(k, i, j)&&v[k]==0) {//判斷8個方向是否能填入,並且是否用過 v[k] = 1; a[i][j] = k; if (j == 3)//到達最後一列記得換行 f(i + 1, 0); else f(i, j + 1); a[i][j] = -9; v[k] = 0; } } } int main(){ for (int i = 0; i < 3; i++)//這裏我將所有數賦值-9,因為第一個和最後一個不需要賦值,避免幹擾 for (int j = 0; j < 4; j++) a[i][j] = -9; f(0, 1); printf("%d", num); return 0; }
#include <bits/stdc++.h> using namespace std; /*本來要判斷八個格子, *但是由於是從左往右從上往下填的, *只要判斷左、左上、上、右上 */ const int dx[]={0,-1,-1,-1}; const int dy[]={-1,-1,0,1}; const int INF=1e9; bool used[10]; int ans=0; int a[5][5]; bool alright(int n,int x,int y) { for (int i=0;i<4;i++) { int xx=x+dx[i],yy=y+dy[i]; if (xx<1||yy<1||xx>3||yy>4) continue; if (abs(n-a[xx][yy])==1) return false; } return true; } void dfs(int x,int y) { if (x==3&&y==4) { ans++; return; } for (int i=0;i<=9;i++) { if (!used[i]&&alright(i,x,y)) { a[x][y]=i; used[i]=true; if (y==4) dfs(x+1,1); else dfs(x,y+1); used[i]=false; a[x][y]=-INF; } } } int main() { for (int i=1;i<=3;i++) { for (int j=1;j<=4;j++) { a[i][j]=-INF; } } dfs(1,2); printf("%d\n",ans); return 0; }
第七屆 藍橋杯 方格填數 dfs