Project Euler Problem 96
問題概要
解法
全てのマスについて現在置くことが出来るもの,と置かれているものを記録してバックトラック法.
実装(C++)
入力データーの最初に50と書いた行を追加し,gridから始まる行を取り除く必要がある.
#include <iostream> #include <cstdio> #include <vector> #include <algorithm> #include <cstring> using namespace std; int popcount(int x){ int res=0; while(x){ x&=x-1; res++; } return res; } short MAP[9][9]; //現状 short canput[9][9];//何が置けるか void clear(){ for(int x=0;x<9;x++)for(int y=0;y<9;y++) MAP[x][y]=0,canput[x][y]=((1<<9)-1)<<1; } void put(int x,int y,int c){ MAP[x][y]=c; int val=~(1<<c); for(int i=0;i<9;i++){ canput[x][i]&=val; canput[i][y]&=val; } for(int i=0;i<3;i++)for(int j=0;j<3;j++){ canput[(x/3)*3+i][(y/3)*3+j]&=val; } } bool dfs(){ //まず選べる種類が最も少ないマスを全探索 int minbits=100,sx,sy; int count=0; for(int x=0;x<9;x++){ for(int y=0;y<9;y++){ if(MAP[x][y]){ count++; continue; } if(popcount(canput[x][y])<minbits){ sx=x;sy=y; minbits=popcount(canput[x][y]); } } } if(count==81){ for(int y=0;y<9;y++){ for(int x=0;x<9;x++){ cout<<MAP[x][y]; } cout<<endl; } return true; }else{ //sx,syに対しておけるものを全て試す short backup[9][9]; memcpy(backup,canput,sizeof(canput)); for(int i=1;i<=9;i++){ if((canput[sx][sy]>>i)&1){ put(sx,sy,i); if(dfs())return true; MAP[sx][sy]=0; memcpy(canput,backup,sizeof(canput)); } } } return false; } int main() { int T; cin>>T; int eulerans=0; for(;T--;){ clear(); vector<string> in(9); for(int i=0;i<9;i++){ cin>>in[i]; } for(int y=0;y<9;y++){ for(int x=0;x<9;x++){ if(in[y][x]-'0')put(x,y,in[y][x]-'0'); } } dfs(); eulerans+=MAP[0][0]*100+MAP[1][0]*10+MAP[2][0]; } cout<<eulerans<<endl; return 0; }