HDU OJ -- LELE的RPG难题(ACM Steps: 3.1.6)

8 篇文章 1 订阅

一、概述

1. 问题描述

有n个格子3种颜色,现在向每个格子着色,条件是:

1)每个格子与相邻格子颜色不同

2)首格与尾格颜色不同

问共有多少种着色方法?

2. 问题链接

HDU OJ -- LELE的RPG难题(ACM Steps: 3.1.6)

3. 问题截图

图1.1  问题截图

二、算法思路

现通过取不同的n值分析并说明算法的思路。

约定如下:

1)下述图中节点表示颜色,其中

V节点表示:第1个格子所用的颜色

X节点表示:第1个格子没有用到的其余两个颜色中的一个

2)图中节点旁边的权值表示当前节点可能的情况种数,即为格子着节点对应颜色的方案数

3)图中的p(i)表示当前为第i个格子着色

4)f(m)表示当n = m时,可行解的个数

 

1. n = 1时

如图2.1所示,当只有一个格子时,它可以着3色,且因为它是第一个格子,故用V节点表示,权值3表示有3种不同的着色方案。

记,f(1) = 3

图2.1  n = 1时满足条件的情况

2. n = 2时

如图2.2所示,p(1),即为第1个格子着色,有3中选择。

p(2),由于要满足条件1,2(如上面的问题描述所述),此时第2个格子只能选择X节点,并且权值为2,表示可选的颜色有2种。

记,f(2) = 3 x 2 = 6

图2.2  n = 2时满足条件的情况

3. n = 3时

如图2.3所示,n = 3时所有可能的情况均已列出,p(1)、p(2)如上所述。

由于条件1,p(3)不能与p(2)的颜色相同,故此时有2种选择,即X节点和V节点(此时X节点对应的颜色与p(2)的X节点对应的颜色不同);

由于条件2,V节点不能选择,图中用虚线表示,表示V节点被剪除,故此时只能选择X节点。

记,f(3) = 3 x 2 x 1 = 6

图2.3 n = 3时满足条件的情况

4. n = 4时

如图2.4所示,p(1)、p(2)如上所述。

由于此时p(3)不是最后一个节点,故有两种选择。

1)当p(3)的X节点向p(4)扩展时,由于条件1、2,此时p(4)只能扩展为X节点,对应的V节点被剪除。

现分析图中用红色圈出的部分,它其实就是n = 3时的情况。n = 3时满足条件的叶子节点必定为X节点,当n = 4时由此X节点向下扩展由于要满足条件1、2,此时也只能扩展为X节点,由n = 3的结果多加了一层唯一的X节点,最后的结果不变,故此部分对应的可行解数目仍然为f(3)。

2)当p(3)的V节点向p(4)扩展时,满足条件1即满足条件2,因为p(4)的相邻节点是V节点,即此节点与第一个格子着色相同,故此时扩展为X节点,且权值为2,表示有两种颜色可以选择。

这个扩展(用蓝色方框框出),其实就是n = 3时被剪除的部分,这部分涉及的可行解的数目为:(3 x 2) x 2 = 12

综上,记f(4) = f(3) + 12 = 18

图2.4  n = 4时满足条件的情况

5. n = 5时

如图2.5所示,如上所述,红色圈出部分对应n = 4时的可行解,蓝色方框表示的是n = 4时剪除的V节点,由于被剪除1个,所以蓝色方框对应部分可以表示为(3 x 2) x (1 x 2),(3 x 2)表示p(1)、p(2)对应的情况数,(1 x 2)表示n = 4时剪除了1个节点,且这个节点必定会派生出两个可行的X节点作为叶子节点。

记,f(5) = f(4) +(3 x 2) x (1 x 2)= 30

图2.5  n = 5时满足条件的情况

 

综上所述,当n > 3时,问题的求解一方面依赖于前面小规模问题解答的数目,一方面依赖于前面所剪除的V节点数,故问题的关键在于表达出n取不同值时前面所剪除的V节点数。

可以从图中看出:

n = 3时,最后一层具有2个节点,其中1个为有效节点,另一个为被剪除节点,记为(a[3],b[3],c[3]=a[3]-b[3])=(2,1,2-1)

n = 4时,最后一层具有4个节点,记为a[4],

有效节点的个数b[4] = (n = 3时的有效节点 )+ (n = 3时被剪除的V节点数)x 2 = b[3] + c[3] x 2,因为上一层每剪除一个V节点,在下一层都对应了两个有效的叶子节点,

剩余的节点数c[4] = a[4] - b[4]

n = m时,(a[m],b[m],c[m]) = ((m - 2)x 2,b[m-1] + c[m-1] x 2,am - bm)

有了被剪除V节点数c[m],f(n)=f(n-1) + c[n-1] x 2 x(3 x 2)

三、算法实现

#include <iostream>

using namespace std;

const int MAXSIZE = 51;
unsigned long long res[MAXSIZE];

int main()
{
    long long twos=2, cur=1, rem=1;

    res[1] = 3;
    res[2] = 6;
    res[3] = 6;

    for(int i=4; i<MAXSIZE; i++){
        res[i] = res[i-1] + (6 * 2 * rem);
        twos *= 2;
        cur += (rem*2);
        rem = twos-cur;
    }

    int n;
    while(cin >> n){
        cout << res[n] << endl;
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值