/* 0代表可以填任意数 e代表只能是奇数 o代表只能填偶数 相同字母的格子必须是同一个数 e,o,0是同样处理的,只不过e,o加入奇数或偶数,0加入全部的1-9 检查符合上述要求的解是否符合同字母同数字即可 */ #include<cstdio> #include<cstring> #include<cmath> #include<vector> using namespace std; const int Row=9; const int MAX_COLOUMN = Row*Row*4+2;//最多出现列数 const int MAX_ROW = Row*Row*Row+2;//最多出现的列数 int res; int cnt[MAX_COLOUMN];//cnt[i]统计第i列1的个数 int most,coloumn; bool ans[MAX_ROW];//ans存放最终选中的行 //跳舞链中的节点 struct Point { int up,down,left,right;//上,下,左,右 int coloumn;//该点所在的列标 int row;//行标 }node[MAX_ROW*MAX_COLOUMN+MAX_COLOUMN]; void init(int m) { int i; for(i=0;i<=m;i++) { node[i].down=i; node[i].up = i; node[i].coloumn=i; node[i].left=i-1; node[i].right=i+1; cnt[i]=0; } node[0].left = m; node[m].right = 0; } void remove(int c)//删除c列上所有1元素所在的行 { node[node[c].right].left=node[c].left; node[node[c].left].right=node[c].right; int t,tt; for(t=node[c].down;t!=c;t=node[t].down)//从上到下从左到右删除该列上的每一非零元素所在行信息 { for(tt = node[t].right;tt!=t;tt=node[tt].right)//删除非零元素所在行 { cnt[node[tt].coloumn]--; node[node[tt].down].up = node[tt].up; node[node[tt].up].down = node[tt].down; } } } void resume(int c)//还原c列上所有1元素所在的行 { int t,tt; for(t=node[c].up;t!=c;t=node[t].up)//从下往上从左到右还原该c列中1所在的行信息 { for(tt=node[t].left;tt!=t;tt=node[tt].left) { cnt[node[tt].coloumn]++; node[node[tt].up].down=tt; node[node[tt].down].up=tt; } } node[node[c].right].left=c; node[node[c].left].right=c; } int tmp[9][9]; typedef pair<int,int> pii; vector<pii> Join[26];//把同字母的坐标放入同一个数组中 void dfs(int k)//k为已经选中的行的数目 { int i,j; //if(k>=most)return ; if(node[coloumn].right == coloumn)//当前跳舞链已为空 { for(int k=0;k<Row;k++) { for(i=0;i<Row;i++) { for(j=0;j<Row;j++) if(ans[(k*Row+i)*Row+j]) tmp[k][i]=j+1; } } int flag=1; for(int i=0;i<26;i++) { for(int j=1;j<Join[i].size();j++) { if(tmp[Join[i][j].first][Join[i][j].second]!=tmp[Join[i][j-1].first][Join[i][j-1].second]) { flag=0; break; } } } if(flag){ res++;}; return ; } int t = coloumn+1; int c; for(i=node[coloumn].right;i!=coloumn;i=node[i].right) { if(cnt[i]<t) { c=i;t=cnt[i]; } } remove(c); for(i = node[c].down;i!=c;i=node[i].down) { for(j=node[i].right;j!=i;j=node[j].right) { remove(node[j].coloumn); } ans[node[j].row]=true; dfs(k+1); ans[node[j].row]=false; for(j=node[j].left;j!=i;j=node[j].left) { resume(node[j].coloumn); } } resume(c); return ; } bool graph[MAX_ROW][MAX_COLOUMN]; void addrow(int i,int j,int k) { int curr = (i*Row+j)*Row+k; graph[curr][(i*Row+j)]=true; graph[curr][Row*Row+i*Row+k]=true; graph[curr][Row*Row*2+j*Row+k]=true; int tmp=(int)(sqrt(Row)); int tr = i/tmp; int tc = j/tmp; graph[curr][Row*Row*3+(tr*tmp+tc)*Row+k]=true; } char str[Row][Row]; int main() { int N,M,i,j,k,ca,nu; scanf("%d",&ca); while(ca--) { res=0; for(int i=0;i<26;i++) Join[i].clear(); for(i=0;i<Row;i++) { scanf("%s",str[i]); } N=Row*Row*Row; M = Row*Row*4; coloumn = M; int cur=coloumn+1;//当前节点编号 init(coloumn); memset(graph,0,sizeof(graph)); for(i=0;i<Row;i++) for(j=0;j<Row;j++) { if(str[i][j]=='o') { for(k=0;k<Row;k=k+2)//遍历每一种颜色 { addrow(i,j,k); } } else if(str[i][j]=='e') { for(k=1;k<Row;k=k+2)//遍历每一种颜色 { addrow(i,j,k); } } else if(str[i][j]>='1'&&str[i][j]<='9') { addrow(i,j,str[i][j]-'1'); } else { if(str[i][j]!=0) { Join[str[i][j]-'a'].push_back(make_pair(i,j)); } for(k=0;k<Row;k++)//遍历每一种颜色 { addrow(i,j,k); } } } for(i=0;i<N;i++) { int start = cur;//记录第i列的开始点编号 int pre = cur;//记录该列中当前1的左边第一个1编号 for(j=0;j<M;j++) { if(graph[i][j])//跳舞链中仅插入非0元素 { int pos = j; node[cur].up = node[pos].up; node[node[pos].up].down = cur; node[cur].down = pos; node[pos].up = cur; cnt[pos]++;//该列1的个数+1 node[cur].coloumn = pos; node[cur].left = pre; node[pre].right = cur; node[cur].right = start; node[start].left=cur; node[cur].row = i; pre=cur++; } } } most = N+1;//记录最少需要选中的行数 memset(ans,false,sizeof(ans)); dfs(0); printf("%d\n",res); } return 0; }
09 harbin现场赛 DLX
最新推荐文章于 2023-04-27 18:30:19 发布