题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5113
题目大意:在一个N * M的棋盘里涂色,要求i颜色要涂ci次。ci求和为N * M.
关键思想:从第一个点开始着色,一行一行涂,注意一旦找到答案后面就不必搜,当剩下个数为n时若有种颜色>n/2上取整就不必搜了(!)。
#include <iostream> #include <iomanip> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <vector> #include <map> #include <queue> #include <stack> #include <set> #include <string> using namespace std; #define MAXN 1005 #define INF 0x3f3f3f3f #define MOD 1000000007 #define LL long long #define PII pair #define MP make_pair #define PB push_back int MAP[7][7]; int c[30];//i种颜色用c[i]次 bool have=false; int T,N,M,K; void print(){ printf("YES\n"); for(int i=1;i<=N;i++){ for(int j=1;j<=M;j++){ if(j==1)printf("%d",MAP[i][j]); else printf(" %d",MAP[i][j]); } printf("\n"); } return ; } void DFS(int x,int y,int tot){ for(int i=1;i<=K;i++){if(c[i]>(tot+1)/2)return ;}//最坏情况(剩一块矩形)的剪枝,很关键 for(int i=1;i<=K;i++){ if(have)return; if(MAP[x-1][y]!=i&&MAP[x][y-1]!=i&&c[i]!=0){//i种颜色有效 MAP[x][y]=i,c[i]--; if(x==N&&y==M){ have=true; print(); return; } if(y+1<=M)DFS(x,y+1,tot-1);//未到行尾涂本行 else DFS(x+1,1,tot-1);//到行尾涂下一行 MAP[x][y]=-1,c[i]++;//恢复 } } return ; } int main(){ scanf("%d",&T); for(int Case=1;Case<=T;Case++){ memset(MAP,-1,sizeof(MAP));//其实按照DFS顺序无需重置 scanf("%d%d%d",&N,&M,&K); bool flag=true; for(int i=1;i<=K;i++){ scanf("%d",&c[i]); if(c[i]>(N*M+1)/2)flag=false;//黑白格都无法满足 } printf("Case #%d:\n",Case); if(!flag){ printf("NO\n"); continue; } have=false; DFS(1,1,N*M); } return 0; }