您的位置:首页 > 其它

LA 3041 Colored Cubes (暴力枚举+贪心)

2016-12-08 19:54 459 查看

LA 3041 Colored Cubes

题目大意:

给n个立方体,每面涂有一颜色,如何尽可能少的涂色,使得所有立方体完全相同.两个立方体相同指存在一种旋转方式使得两个立方体完全一致.

题目分析:

n<=4,比较小,所以可以想到以某一个立方体为标准,不旋转这个标准立方体,枚举其他立方体旋转情况,使得在某一情况下的花费最少.

当然问题就在于如何枚举出某一立方体的所有旋转形态,以每一个面为正面,存在4种形态,共计6*4=24种形态.这个计算形态个数的方法实际上也提供了一种可行思路:先枚举某一个面是那个面,再旋转0~3次统计形态个数,制成常量表以供使用.

maker制表代码:

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int up[]={2,1,5,0,4,3};//向上翻
const int left[]={4,0,2,3,5,1};//向左翻

void rot(const int* T,int* p)//p序列按照T方式翻转
{
int q[10];
for(int i=0;i<6;i++) q[i]=p[i];
for(int i=0;i<6;i++) p[i]=T[q[i]];
}

void init()//制表
{
int p0[]={0,1,2,3,4,5};
printf("const int poses[24][6]={\n");
for(int i=0;i<6;i++) {
int p[10];
for(int j=0;j<6;j++) p[j]=p0[j];
switch(i) {//不同面朝上的处理
case 0:rot(up,p);break;
case 1:rot(left,p);rot(up,p);break;
case 3:rot(up,p);rot(up,p);break;
case 4:rot(left,p);rot(left,p);rot(left,p);rot(up,p);break;
case 5:rot(left,p);rot(left,p);rot(up,p);break;
}
for(int j=0;j<4;j++)
printf("{%d,%d,%d,%d,%d,%d},",p[0],p[1],p[2],p[3],p[4],p[5]),rot(left,p);
printf("\n");
}
printf("};");
}

int main()
{
init();
return 0;
}


代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;

const int maxn=4;
const int poses[24][6]={//maker制表代码制好的常量表
{2,1,5,0,4,3},{2,0,1,4,5,3},{2,4,0,5,1,3},{2,5,4,1,0,3},
{4,2,5,0,3,1},{5,2,1,4,3,0},{1,2,0,5,3,4},{0,2,4,1,3,5},
{0,1,2,3,4,5},{4,0,2,3,5,1},{5,4,2,3,1,0},{1,5,2,3,0,4},
{3,4,5,0,1,2},{3,5,1,4,0,2},{3,1,0,5,4,2},{3,0,4,1,5,2},
{1,3,5,0,2,4},{0,3,1,4,2,5},{4,3,0,5,2,1},{5,3,4,1,2,0},
{5,1,3,2,4,0},{1,0,3,2,5,4},{0,4,3,2,1,5},{4,5,3,2,0,1},
};

vector<string>names;

int ID(const char* name)//将颜色转换成数字编号
{
string s(name);
int d=names.size();
for(int i=0;i<d;i++)
if(s==names[i]) return i;
names.push_back(s);
return d;
}

int pre[maxn][6],n;//pre记录一开始的颜色分布
int rot[maxn],color[maxn][6],ans;//rot记录每个数组旋转情况,color记录旋转后的颜色分布

void check()
{
for(int i=0;i<n;i++)
for(int j=0;j<6;j++)
color[i][poses[rot[i]][j]]=pre[i][j];
int tot=0;
for(int i=0;i<6;i++) {
int cnt[maxn*6];//统计各种颜色出现的次数,选择次数最多的那种颜色作为标准
memset(cnt,0,sizeof(cnt));
int maxs=0;
for(int j=0;j<n;j++) maxs=max(maxs,++cnt[color[j][i]]);
tot+=n-maxs;//需要涂色的面就是总个数-最多的颜色的面个数
}
ans=min(ans,tot);
}

void dfs(int d)//dfs枚举旋转情况
{
if(d==n) check();
else for(int i=0;i<24;i++) rot[d]=i,dfs(d+1);
}

int main()
{
while(scanf("%d",&n)==1&&n) {
names.clear();
for(int i=0;i<n;i++) for(int j=0;j<6;j++) {
char name[30];
scanf("%s",name);
pre[i][j]=ID(name);
}
ans=n*6;
rot[0]=0;//0号立方体不旋转
dfs(1);
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: