目录
  • 日历拼图C++解法
    • 0.介绍
    • 1.思路
      • a) 用字符串数组存8种拼图块
      • b) 获得8种拼图块的8种放置方式
      • c) 判断某一个位置是否可以放置对应的拼图块。
      • d) 放置拼图块
      • e) 回溯放置
      • f) 深度优先搜索dfs
    • 2.完整程序
    • 总结

      日历拼图C++解法

      0.介绍

      任何一个日期都可以用8块拼图拼起来。

      C++日历拼图的解法你了解吗

      如12月3日:

      C++日历拼图的解法你了解吗

      1.思路

      主要的思想就是深度优先搜索。

      a) 用字符串数组存8种拼图块

      char a[9][5][5]={
      	{{'.','.','.','.'},
      	{'.','.','.','.'},
      	{'.','.','.','.'},
      	{'.','.','.','.'}},	
      	
      	{{'1','1','1','1'},
      	{'1','.','.','.'},
      	{'.','.','.','.'},
      	{'.','.','.','.'}},	
      		
      	{{'2','2','2','.'},
      	{'2','2','.','.'},
      	{'.','.','.','.'},
      	{'.','.','.','.'}},
      	
      	{{'3','3','.','.'},
      	{'.','3','3','3'},
      	{'.','.','.','.'},
      	{'.','.','.','.'}},
      	
      	{{'4','.','.','.'},
      	{'4','4','4','.'},
      	{'.','.','4','.'},
      	{'.','.','.','.'}},
      	
      	{{'5','5','5','.'},
      	{'5','.','.','.'},
      	{'5','.','.','.'},
      	{'.','.','.','.'}},	
       
      	{{'6','6','6','6'},
      	{'.','6','.','.'},
      	{'.','.','.','.'},
      	{'.','.','.','.'}},
      	
      	{{'7','7','7','.'},
      	{'7','7','7','.'},
      	{'.','.','.','.'},
      	{'.','.','.','.'}},
      	
      	{{'8','8','8','.'},
      	{'8','.','8','.'},
      	{'.','.','.','.'},
      	{'.','.','.','.'}}};
      

      b) 获得8种拼图块的8种放置方式

      这里我使用旋转加翻转实现的。

      [2] 最开始为第一个,然后翻转得到第二个。

      [3] 再翻转回来,再顺时针90度得到第三个。

      重复[2] [3] 步骤就可以得到8种放置方式。

      翻转代码

      也就是左右交换。

      void filp(char a[5][5]){
      	for(int i=0;i<4;i++)	
      		for(int j=0;j<2;j++){
      			swap(a[i][j],a[i][3-j]);
      		}	
      }
      

      旋转代码

      这里我是顺时针旋转90度。

      void rot(char a[5][5]){
      	char b[5][5];
      	for(int i=0;i<4;i++){
      		for(int j=0;j<4;j++)
      			b[i][j] = a[3-j][i];	
      	}
      		for(int i=0;i<4;i++)
      		for(int j=0;j<4;j++) a[i][j] = b[i][j];
      }
      

      c) 判断某一个位置是否可以放置对应的拼图块。

      这里我们以左上角第一个非.的位置为起点,然后进行判断。

      bool candown(int x,int y,int i,int j){
      	int sx = -1, sy = -1;
      	for(int xx=0;xx<4;xx++)
      		for(int yy=0;yy<4;yy++){
      			if(b[i][j][xx][yy] != '.'){
      				sx = xx;
      				sy = yy;
      				int kx =sx,ky= sy;
      				while(kx<4 && ky<4){
      						int nx = x + kx-sx;
      						int ny = y + ky-sy;
      						//如果要覆盖
      						if(b[i][j][kx][ky]!='.'){
      							if(nx<0 || ny<0) return false;
      							if(nx<2 && ny<=5){
      								if(mp[nx][ny]!='.') return false;
      							//	mp[nx][ny] = b[i][j][kx][ky];
      							}
      							else if(nx<=5 && nx>=2 && ny<=6){
      								if(mp[nx][ny]!='.') return false;
      							//	mp[nx][ny] = b[i][j][kx][ky];								
      							}
      							else if(nx==6 && ny<=2){
      								if(mp[nx][ny]!='.') return false;
      							//	mp[nx][ny] = b[i][j][kx][ky];								
      							}
      							else return false;
      						}
      						if(ky==3){
      							kx++,ky=0;
      						}
      						else ky++;
      					}
      				return true;
      			}
      		}
      	return false;
      }
      

      d) 放置拼图块

      与第c 步类似。

      void down(int x,int y,int i,int j){
      	for(int xx=0;xx<4;xx++)
      		for(int yy=0;yy<4;yy++){
      			if(b[i][j][xx][yy] != '.'){
      				int kx =xx,ky= yy;
      				while(kx<4 && ky<4){
      						int nx = x + kx-xx;
      						int ny = y + ky-yy;
      						if(b[i][j][kx][ky]!='.'){
      							mp[nx][ny] = b[i][j][kx][ky];								
      						}
      						if(ky==3){
      							kx++,ky=0;
      						}
      						else ky++;
      					}
      				return;
      			}
      		}	
      }
      

      e) 回溯放置

      与 d 步类似。

      void undown(int x,int y,int i,int j){
      	for(int xx=0;xx<4;xx++)
      		for(int yy=0;yy<4;yy++){
      			if(b[i][j][xx][yy] != '.'){
      								int kx =xx,ky= yy;
      				while(kx<4 && ky<4){
      						int nx = x + kx-xx;
      						int ny = y + ky-yy;
      						if(b[i][j][kx][ky]!='.'){
      							mp[nx][ny] = '.';								
      						}
      						if(ky==3){
      							kx++,ky=0;
      						}
      						else ky++;
      					}
      				return;
      			}
      		}	
      }
      

      f) 深度优先搜索dfs

      这里我用一维代替二维坐标,然后dfs的时候求出对应的位置。

      然后就是简单带回溯的搜索了。

      void dfs(int id){
      	int x = id/7;
      	int y = id%7;
      	if(x<2 && y==6){
      		dfs(id+1);
      	}
      	if(x==6 && y==3){
      	//	printf("Success!\n");
      		for(int i=0;i<7;i++){
      			for(int j=0;j<7;j++){
      				if(mp[i][j]=='.') continue;
      				putchar(mp[i][j]);
      			}
      			putchar('\n');
      		}
      		exit(0);
      	}
      	if(mp[x][y]!='.') dfs(id+1);
      	for(int i=1;i<=8;i++){		
      		if(!vis[i]){
      			for(int j=1;j<=8;j++){
      				if(candown(x,y,i,j)){
      					down(x,y,i,j);
      					vis[i] = 1;
      					dfs(id+1);
      					undown(x,y,i,j);
      					vis[i] = 0;
      				}
      			}	
      		}
      	}
      }
      

      2.完整程序

      我这里找到解就退出,如果想要找到每个解的所有情况,可以自行修改代码。即对应dfs里的exit(0) 去掉。

      #include<bits/stdc++.h>
      using namespace std;
      typedef long long ll;
      typedef unsigned long long ull; 
      const int N=1e3+5,M=2e8+5,inf=0x3f3f3f3f,mod=1e9+7;
      const int hashmod[8] = {802653189,805306857,1610612781,998288353};
      #define mst(a,b) memset(a,b,sizeof a)
      #define db double
      #define PII pair<int,int>
      #define PLL pair<ll,ll>
      #define x first
      #define y second
      #define pb emplace_back
      #define SZ(a) (int)a.size()
      #define rep(i,a,b) for(int i=a;i<=b;++i)
      #define per(i,a,b) for(int i=a;i>=b;--i)
      #define IOS ios::sync_with_stdio(false),cin.tie(nullptr) 
      void Print(int *a,int n){
      	for(int i=1;i<n;i++)
      		printf("%d ",a[i]);
      	printf("%d\n",a[n]); 
      }
      template <typename T>		//x=max(x,y)  x=min(x,y)
      void cmx(T &x,T y){
      	if(x<y) x=y;
      }
      template <typename T>
      void cmn(T &x,T y){
      	if(x>y) x=y;
      }
      char a[9][5][5]={
      	{{'.','.','.','.'},
      	{'.','.','.','.'},
      	{'.','.','.','.'},
      	{'.','.','.','.'}},	
      	
      	{{'1','1','1','1'},
      	{'1','.','.','.'},
      	{'.','.','.','.'},
      	{'.','.','.','.'}},	
      		
      	{{'2','2','2','.'},
      	{'2','2','.','.'},
      	{'.','.','.','.'},
      	{'.','.','.','.'}},
      	
      	{{'3','3','.','.'},
      	{'.','3','3','3'},
      	{'.','.','.','.'},
      	{'.','.','.','.'}},
      	
      	{{'4','.','.','.'},
      	{'4','4','4','.'},
      	{'.','.','4','.'},
      	{'.','.','.','.'}},
      	
      	{{'5','5','5','.'},
      	{'5','.','.','.'},
      	{'5','.','.','.'},
      	{'.','.','.','.'}},	
       
      	{{'6','6','6','6'},
      	{'.','6','.','.'},
      	{'.','.','.','.'},
      	{'.','.','.','.'}},
      	
      	{{'7','7','7','.'},
      	{'7','7','7','.'},
      	{'.','.','.','.'},
      	{'.','.','.','.'}},
      	
      	{{'8','8','8','.'},
      	{'8','.','8','.'},
      	{'.','.','.','.'},
      	{'.','.','.','.'}}};
      char b[9][9][5][5];
      void filp(char a[5][5]){
      	for(int i=0;i<4;i++)	
      		for(int j=0;j<2;j++){
      			swap(a[i][j],a[i][3-j]);
      		}	
      }
      void pr(char a[5][5]){
      	for(int i=0;i<4;i++)
      	{
      		for(int j=0;j<4;j++){
      			putchar(a[i][j]);
      		}
      		putchar('\n');
      	}
      }
      void rot(char a[5][5]){
      	char b[5][5];
      	for(int i=0;i<4;i++){
      		for(int j=0;j<4;j++)
      			b[i][j] = a[3-j][i];	
      	}
      		for(int i=0;i<4;i++)
      		for(int j=0;j<4;j++) a[i][j] = b[i][j];
      }
      char mp[8][8]={
      	".......",
      	".......",
      	".......",
      	".......",
      	".......",
      	".......",
      	".......",
      };
      
      void cp(char a[5][5],char b[5][5]){
      	for(int i=0;i<4;i++){
      		for(int j=0;j<4;j++)
      			a[i][j] = b[i][j];
      		a[i][4]='\0';
      		}
      }
      int vis[9];
      bool candown(int x,int y,int i,int j){
      	int sx = -1, sy = -1;
      	for(int xx=0;xx<4;xx++)
      		for(int yy=0;yy<4;yy++){
      			if(b[i][j][xx][yy] != '.'){
      				sx = xx;
      				sy = yy;
      				int kx =sx,ky= sy;
      				while(kx<4 && ky<4){
      						int nx = x + kx-sx;
      						int ny = y + ky-sy;
      						//如果要覆盖
      						if(b[i][j][kx][ky]!='.'){
      							if(nx<0 || ny<0) return false;
      							if(nx<2 && ny<=5){
      								if(mp[nx][ny]!='.') return false;
      							//	mp[nx][ny] = b[i][j][kx][ky];
      							}
      							else if(nx<=5 && nx>=2 && ny<=6){
      								if(mp[nx][ny]!='.') return false;
      							//	mp[nx][ny] = b[i][j][kx][ky];								
      							}
      							else if(nx==6 && ny<=2){
      								if(mp[nx][ny]!='.') return false;
      							//	mp[nx][ny] = b[i][j][kx][ky];								
      							}
      							else return false;
      						}
      						if(ky==3){
      							kx++,ky=0;
      						}
      						else ky++;
      					}
      				return true;
      			}
      		}
      	return false;
      }
      void down(int x,int y,int i,int j){
      	for(int xx=0;xx<4;xx++)
      		for(int yy=0;yy<4;yy++){
      			if(b[i][j][xx][yy] != '.'){
      				int kx =xx,ky= yy;
      				while(kx<4 && ky<4){
      						int nx = x + kx-xx;
      						int ny = y + ky-yy;
      						if(b[i][j][kx][ky]!='.'){
      							mp[nx][ny] = b[i][j][kx][ky];								
      						}
      						if(ky==3){
      							kx++,ky=0;
      						}
      						else ky++;
      					}
      				return;
      			}
      		}	
      }
      void undown(int x,int y,int i,int j){
      	for(int xx=0;xx<4;xx++)
      		for(int yy=0;yy<4;yy++){
      			if(b[i][j][xx][yy] != '.'){
      								int kx =xx,ky= yy;
      				while(kx<4 && ky<4){
      						int nx = x + kx-xx;
      						int ny = y + ky-yy;
      						if(b[i][j][kx][ky]!='.'){
      							mp[nx][ny] = '.';								
      						}
      						if(ky==3){
      							kx++,ky=0;
      						}
      						else ky++;
      					}
      				return;
      			}
      		}	
      }
      void dfs(int id){
      	int x = id/7;
      	int y = id%7;
      	if(x<2 && y==6){
      		dfs(id+1);
      	}
      	if(x==6 && y==3){
      	//	printf("Success!\n");
      		for(int i=0;i<7;i++){
      			for(int j=0;j<7;j++){
      				if(mp[i][j]=='.') continue;
      				putchar(mp[i][j]);
      			}
      			putchar('\n');
      		}
      		exit(0);
      	}
      	if(mp[x][y]!='.') dfs(id+1);
      	for(int i=1;i<=8;i++){		
      		if(!vis[i]){
      			for(int j=1;j<=8;j++){
      				if(candown(x,y,i,j)){
      					down(x,y,i,j);
      					vis[i] = 1;
      					dfs(id+1);
      					undown(x,y,i,j);
      					vis[i] = 0;
      				}
      			}	
      		}
      	}
      }
      int main(){
      	int m,d;
      	scanf("%d%d",&m,&d);
      	//初始化
      	mp[m>6][(m-1)%6] = '0';
      	mp[((d-1)/7)+2][(d-1)%7] = '0';
      	//得到每个拼图的所有情况
      	for(int i=1;i<=8;i++){
      			cp(b[i][1],a[i]);filp(a[i]);
      			cp(b[i][2],a[i]);filp(a[i]);rot(a[i]);
      			cp(b[i][3],a[i]);filp(a[i]);
      			cp(b[i][4],a[i]);filp(a[i]);rot(a[i]);
      			cp(b[i][5],a[i]);filp(a[i]);
      			cp(b[i][6],a[i]);filp(a[i]);rot(a[i]);
      			cp(b[i][7],a[i]);filp(a[i]);
      			cp(b[i][8],a[i]);					
      	}
      	dfs(0);
      	return 0;
      }
      
      

      总结

      本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注的更多内容!     

      声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。