洛谷 P1780 染色的立方体 题解报告

题目传送门

赛时经历

赛时没有注意复杂度,以为暴力搜索会超时,于是喜提爆零。

思路

暴力搜索加贪心。

暴力搜索部分

复杂度证明

大家应该都玩过骰子吧,玩久了就会发现,一个骰子如果分出方向的话,一共有 \(24\) 种摆放方法。

如何证明?

用排列组合,我们可以假定 \(1\) 号面的朝向不动,可将与 \(1\) 号面相邻的 4 个面进行旋转,则有 4 种可能;而 \(1\) 号面一共有 6 个朝向,则可得一共有 \(4 \times 6 = 24\) 种摆放可能。

由题意得立方体数量 \(1 \le n \le 4\),则最多可能情况有 \(24^4 = 331776\) 完全不会超时。

代码片段

我们可以通过打表列出立方体的 \(24\) 种变换方式,这样在变换时,可通过数组进行变换。
以下给出变换数组:

int ch[24][6]={
{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},
{5,1,3,2,4,0},
{1,0,3,2,5,4},
{0,4,3,2,1,5},
{4,5,3,2,0,1},
{1,3,5,0,2,4},
{0,3,1,4,2,5},
{4,3,0,5,2,1},
{5,3,4,1,2,0},
{3,4,5,0,1,2},
{3,5,1,4,0,2},
{3,1,0,5,4,2},
{3,0,4,1,5,2},
};

贪心部分

在确定了 \(n\) 个骰子的一种情况后,对于每一个朝向,找相同颜色面数量最多的颜色,将不是该颜色的面改为该颜色,即可做到对于该朝向修改颜色次数最少,再遍历每一个朝向,即可得到答案。

误区

本人在进行贪心时,以为一定要将所有骰子统一为其中一个骰子的所有面的颜色,并获得了 \(40\) 分的好成绩。

实际则不然,如此贪心是错误的,题目只要求所有相同朝向的面颜色相同即可。

所以切不可像本人一样为省去遍历一个骰子的时间,痛失 \(60\) 分。

代码实现

基于如上思路,便可得到以下通过代码:

#include<bits/stdc++.h>
using namespace std;
int ch[24][6]={
{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},
{5,1,3,2,4,0},
{1,0,3,2,5,4},
{0,4,3,2,1,5},
{4,5,3,2,0,1},
{1,3,5,0,2,4},
{0,3,1,4,2,5},
{4,3,0,5,2,1},
{5,3,4,1,2,0},
{3,4,5,0,1,2},
{3,5,1,4,0,2},
{3,1,0,5,4,2},
{3,0,4,1,5,2},
};
map<string,int>mp;
int arr[10][10],t[10][10],cnt,ANS=INT_MAX,n;
int check()
{
	int cnt=0,maxn=0,sum[105];
	for(int i=0;i<6;++i)
	{
		maxn=0;
		memset(sum,0,sizeof sum);	
		for(int j=1;j<=n;++j)
		{
			sum[t[j][i]]++;
			maxn=max(maxn,sum[t[j][i]]);
		}
		cnt+=n-maxn;
	}
	return cnt;
}
void solve(int k)
{
	if(k>n)
	{
		ANS=min(ANS,check());
		return ;
	}
	int cnt;
	for(int i=0;i<24;++i)
	{
		cnt=0;
		for(int j=0;j<6;++j)
		{
			t[k][j]=arr[k][ch[i][j]];
		}
		solve(k+1);
	}
	return ;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
	cin>>n; 
    while(n!=0)
    {
    	for(int i=1;i<=n;++i)
    	{
    		for(int j=0;j<6;++j)
    		{
    			string s;
    			cin>>s;
    			if(mp[s]==0)
    			{
    				mp[s]=++cnt;
				}
				arr[i][j]=mp[s];
			}
		}
		solve(1);
		cout<<ANS<<"\n";
		cnt=0;
		ANS=INT_MAX;
		mp.clear();
		cin>>n;
	}
	return 0;
}

最后感谢您的留步与观看,希望本篇题解能够帮到您。

posted @ 2025-11-04 12:46  xianxi_zx  阅读(4)  评论(0)    收藏  举报