题意:给你一个n阶立方体,某些单位立方体缺失(剩下部分可以不连通)。未缺失的单位立方体6个面的颜色均相同。现给出该n阶立方体的6个面的视图,求这个立方体最多可以包含多少个单位立方体。
由于n <= 10,所以我想直接暴力。当然,并不是暴力枚举每个立方体是否存在,那样的话时间复杂度将会是O(2^(n^3)),肯定TLE。我们假设这个立方体是完整的,然后规定一种操作:当前状态下依次判断每一个立方体是否符合所给出的视图。如果某个单位立方体不符合,则令该单位立方体缺失,然后重复这个操作。直到某次操作没有减少任何一个单位立方体,则剩下的就是最大可以包含的单位立方体数。判断单位立方体是否符合视图(即是否应该缺失)用如下规则:
1、若该单位立方体向6个面投影的视图中对应的位置为 '.' ,则该立方体缺失。
2、若该单位立方体向某个面投影的路径上有其他立方体存在,则该单位立方体向这个面的投影不用考虑。
3、若该单位立方体向某个面投影的路径上没有其他立方体存在,则该单位立方体的颜色必须与向这个面投影的视图的对应位置的颜色一样。否则该单位立方体缺失。
4、若该单位立方体向6个面投影均满足视图,则该单位立方体可以不缺失。
这样每次操作要么不减少立方体(即得出答案)要么至少减少一个立方体,最多只需要重复n^3次操作,而每次操作最多需要遍历n^3个单位立方体坐标,时间复杂度为O(n^6)。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
using namespace std;
const int MAX = 15;
int n;
char see[6][MAX][MAX]; //视图颜色
bool exist[MAX][MAX][MAX]; //每个单位立方体是否可以存在
char color[MAX][MAX][MAX]; //每个单位立方体的颜色
void initial()
{
memset(exist, true, sizeof(exist));
for(int x = 0; x < n; x++)
{
for(int y = 0; y < n; y++)
{
for(int z = 0; z < n; z++)
color[x][y][z] = '0'; //初始化标记为未知颜色,之后根据视图逐个上色
}
}
}
bool judge(int x, int y, int z) //判断当前位置立方体是否合法
{
if(see[0][z][x] == '.' ||
see[1][z][y] == '.' ||
see[2][z][n - 1 - x] == '.' ||
see[3][z][n - 1 - y] == '.' ||
see[4][y][x] == '.' ||
see[5][n - 1 - y][x] == '.') //此处能被看穿
return false;
bool flag = false; //标记投影的那一面是否被其它存在的立方体遮挡
//投影到前面
for(int i = y + 1; i < n; i++)
{
if(exist[x][i][z])
{
flag = true;
break;
}
}
if(!flag && color[x][y][z] != see[0][z][x])
{
if(color[x][y][z] == '0')
color[x][y][z] = see[0][z][x];
else
return false;
}
flag = false;
//投影到左面
for(int i = 0; i < x; i++)
{
if(exist[i][y][z])
{
flag = true;
break;
}
}
if(!flag && color[x][y][z] != see[1][z][y])
{
if(color[x][y][z] == '0')
color[x][y][z] = see[1][z][y];
else
return false;
}
flag = false;
//投影到后面
for(int i = 0; i < y; i++)
{
if(exist[x][i][z])
{
flag = true;
break;
}
}
if(!flag && color[x][y][z] != see[2][z][n - 1 - x])
{
if(color[x][y][z] == '0')
color[x][y][z] = see[2][z][n - 1 - x];
else
return false;
}
flag = false;
//投影到右面
for(int i = x + 1; i < n; i++)
{
if(exist[i][y][z])
{
flag = true;
break;
}
}
if(!flag && color[x][y][z] != see[3][z][n - 1 - y])
{
if(color[x][y][z] == '0')
color[x][y][z] = see[3][z][n - 1 - y];
else
return false;
}
flag = false;
//投影到顶面
for(int i = 0; i < z; i++)
{
if(exist[x][y][i])
{
flag = true;
break;
}
}
if(!flag && color[x][y][z] != see[4][y][x])
{
if(color[x][y][z] == '0')
color[x][y][z] = see[4][y][x];
else
return false;
}
flag = false;
//投影到底面
for(int i = z + 1; i < n; i++)
{
if(exist[x][y][i])
{
flag = true;
break;
}
}
if(!flag && color[x][y][z] != see[5][n - 1 - y][x])
{
if(color[x][y][z] == '0')
color[x][y][z] = see[5][n - 1 - y][x];
else
return false;
}
return true; //满足各个方向投影的视图
}
void input()
{
for(int i = 0; i < n; i++)
{
for(int j = 0; j < 6; j++)
scanf("%s", see[j][i]);
}
}
void solve()
{
initial();
int ans = n*n*n;
bool flag = true;
while(flag && ans)
{
flag = false;
for(int x = 0; x < n && !flag; x++)
{
for(int y = 0; y < n && !flag; y++)
{
for(int z = 0; z < n && !flag; z++)
{
if(exist[x][y][z] && !judge(x, y, z)) //此处立方体不满足所给视图
{
flag = true;
exist[x][y][z] = false;
ans--;
}
}
}
}
}
printf("Maximum weight: %d gram(s)\n", ans);
}
int main()
{
while(scanf("%d", &n) && n != 0)
{
input();
solve();
}
return 0;
}