题目描述:
给出k种颜色,给n*m的格子染色,保证任意一个格子与周围格子颜色不同。
大致思路:
这个题可以搜索+剪枝过,但是更巧妙的方法就是构造法,构造的过程很简单,先将n*m的格子黑白染色,使得任意黑格子周围都是白格子,之后挑最大的颜色给黑格子染色,如果染完还剩的话就一定无解,如果染完,就挑数量最少的颜色继续染黑格子,之后将剩下的颜色任意放在白格子里就可以了。但是这样构造有一个小问题,就是在行过少的时候,比如5*2的格子,三种颜色,分别是3 3 4,这样按照这个过程就会出问题,所以就想到了保证不会出错的方法,就是当行小于列的时候,将行列交换,染完颜色之后转置输出。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <string>
using namespace std;
typedef long long ll;
typedef vector<int> vint;
#define RD(x) scanf("%d",&x)
#define CLR(a,b) memset(a,b,sizeof(a))
int n,m,k;
int a[100];
int mm[10][10];
int main() {
//freopen("in.txt","r",stdin);
int T;
cin>>T;
for (int t = 1; t <= T; t++) {
CLR(mm,0);
cin>>n>>m>>k;
int tmpn = n,tmpm = m;
if (n < m) swap(n,m);
//cout<<n<<" "<<m<<" "<<k<<endl;
bool flag = false;
for (int i = 1; i <= k; i++) RD(a[i]);
if (n == 2 && m == 3 && k == 3 && a[1] == 2 && a[2] == 2) flag = true;
int tmp = 1;
for (int i = 1; i <= k; i++) {
if (a[i] > a[tmp]) tmp = i;
}
int sum = 0;
if (m % 2 && n % 2) {
sum = (m/2+1)*(n/2+1)+(m/2)*(n/2);
}
else if (m % 2) {
sum = (m/2+1+m/2)*(n/2);
}
else sum = (m/2)*n;
printf("Case #%d:\n",t);
if (a[tmp] > sum) {
printf("NO\n");
continue;
}
//cout<<sum<<" "<<tmp<<endl;
sum -= a[tmp];
for (int i = 1; i <= n; i++) {
if (i % 2 == 0) {
for (int j = 2; j <= m; j += 2) {
mm[i][j] = tmp;
a[tmp]--;
//cout<<i<<" "<<j<<mm[2][1]<<endl;
if (a[tmp] == 0) break;
}
}
else {
for (int j = 1; j <= m; j += 2) {
mm[i][j] = tmp;
a[tmp]--;
//cout<<i<<" "<<j<<mm[2][1]<<endl;
if (a[tmp] == 0) break;
}
}
if (a[tmp] == 0) break;
}
while (sum > 0) {
tmp = 1;
while (a[tmp] == 0) tmp++;
for (int i = tmp + 1; i <= k; i++) if (a[i] < a[tmp] && a[i]) tmp = i;
if (sum < a[tmp]) {
sum = 0;
for (int i = 1; i <= n; i++) {
if (i % 2 == 0) {
for (int j = 2; j <= m; j += 2) {
if (mm[i][j] != 0) continue;
mm[i][j] = tmp;
a[tmp]--;
if (a[tmp] == 0) break;
}
}
else {
for (int j = 1; j <= m; j += 2) {
if (mm[i][j] != 0) continue;
mm[i][j] = tmp;
a[tmp]--;
if (a[tmp] == 0) break;
}
}
if (a[tmp] == 0) break;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (mm[i][j] != 0) continue;
mm[i][j] = tmp;
a[tmp]--;
if (a[tmp] == 0) break;
}
if (a[tmp] == 0) break;
}
}
else {
sum -= a[tmp];
for (int i = 1; i <= n; i++) {
if (i % 2 == 0) {
for (int j = 2; j <= m; j += 2) {
if (mm[i][j] != 0) continue;
mm[i][j] = tmp;
a[tmp]--;
if (a[tmp] == 0) break;
}
}
else {
for (int j = 1; j <= m; j += 2) {
if (mm[i][j] != 0) continue;
mm[i][j] = tmp;
a[tmp]--;
if (a[tmp] == 0) break;
}
}
if (a[tmp] == 0) break;
}
}
}
tmp = 1;
while (a[tmp] == 0) tmp++;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (mm[i][j] != 0) continue;
mm[i][j] = tmp;
a[tmp]--;
while (a[tmp] == 0) tmp++;
}
}
if (flag) {
mm[1][1] = mm[2][3] = 1;
mm[1][2] = mm[2][1] = 2;
mm[1][3] = mm[2][2] = 3;
}
/*flag = true;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (mm[i][j] == mm[i-1][j] || mm[i][j] == mm[i+1][j] || mm[i][j] == mm[i][j-1] || mm[i][j] == mm[i][j+1]) flag = false;
}
}
if (flag == false) {
printf("NO\n");
continue;
}*/
printf("YES\n");
if (tmpn == n) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (j != 1) printf(" %d",mm[i][j]);
else printf("%d",mm[i][j]);
}
printf("\n");
}
}
else {
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (j != 1) printf(" %d",mm[j][i]);
else printf("%d",mm[j][i]);
}
printf("\n");
}
}
}
}