超级码力在线编程大赛初赛 第4场 1.十字绣
https://tianchi.aliyun.com/oj/15193368247341694/87525024802738980
搜索
我用的是搜索行,检验列
搜行的时候只考虑行的限制,检验列的时候只考虑列的限制
每次只考虑第一行到当前这一行,以及到当前列是不是满足要求
搜索每一个连续区间
假设现在是第x行的第y个连续区间
先将这一个连续区间定好位置
假设本行上一个连续区间到了第a列,这一个连续区间到了第b列
然后检验本行[a+1,b]内的每一列i,如果第i列从第1行到这一行,都还不违背列的限制
那就认为是合法的
注意如果到了最后一行,要判断是否已经满足本列的限制
剪枝只加了1个
预处理每一行每一个连续段后面至少需要多少列
#include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define N 27 int n,m; int hh[N][N],sh[N],ll[N][N],sl[N]; bool mp[N][N]; int sneed[N][N]; int ok=0; bool check(int x,int y) { int now=1,tmp=0; for(int i=1;i<=x;++i) if(mp[i][y]) { if(now>sl[y]) return false; tmp++; if(tmp>ll[y][now]) return false; } else { if(!tmp) continue; if(tmp!=ll[y][now]) return false; tmp=0; now++; } if(x==n) { if(tmp) return (now==sl[y] && tmp==ll[y][now]); else return now==sl[y]+1; } return true; } bool color(int x,int sum,int pos,int last) { int t=pos+sum-1; for(int i=pos;i<=t;++i) mp[x][i]=true; for(int i=max(1,last+1);i<=t;++i) if(!check(x,i)) return false; return true; } void dfs(int x,int y,int last) { if(x==n+1) { for(int i=1;i<=n;++i) { for(int j=1;j<=m;++j) if(mp[i][j]) printf("*"); else printf("."); printf("\n"); } exit(0); } if(y>sh[x]) { dfs(x+1,1,-1); return; } bool tmp[N][N]; for(int i=last+2;i+sneed[x][y]-1<=m;++i) { memcpy(tmp,mp,sizeof(mp)); if(color(x,hh[x][y],i,last)) { /*for(int k=1;k<=n;++k) { for(int j=1;j<=m;++j) if(mp[k][j]) printf("*"); else printf("."); printf("\n"); } printf("\n\n"); ok++;*/ if(y==sh[x]) dfs(x+1,1,-1); else dfs(x,y+1,i+hh[x][y]-1); } memcpy(mp,tmp,sizeof(tmp)); } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) { scanf("%d",&sh[i]); for(int j=1;j<=sh[i];++j) scanf("%d",&hh[i][j]); } for(int i=1;i<=m;++i) { scanf("%d",&sl[i]); for(int j=1;j<=sl[i];++j) scanf("%d",&ll[i][j]); } for(int i=1;i<=n;++i) for(int j=sh[i];j;--j) if(j==sh[i]) sneed[i][j]=hh[i][j]; else sneed[i][j]=sneed[i][j+1]+1+hh[i][j]; dfs(1,1,-1); }