n色方柱问题

#include<iostream>
#include<fstream>
#include<algorithm>
using namespace std;

const int MAX = 50;
int board[MAX][6];  //存储n个立方体各面的颜色
int solu[MAX][6];   //存储解
int n;  //立方体个数、颜色种数
int ans = 0;  //解的个数
int used[MAX];
char color[MAX];

//找到一个解后,输出
void out(int edge[])
{
    int i, j, k, a, b, c, d;
    for(i=0; i<2; i++) //2个子图
    {
        for(j=0; j<n; j++)
            used[j] = 0;
        do{
            j = 0;
            d = c = -1;  
            while(j<n && used[j]>0) //找下一条未用的边
                j++;
            if(j < n)
                do{
                    a = board[j][edge[i*n+j]*2];
                    b = board[j][edge[i*n+j]*2+1];
                    if(b == d)  //如果上一条边的终点与b相同,说明b为始点,交换,保证a为始点
                        swap(a, b);  //保证有向边的始点对应于前面和左面,终点对应于背面和右面
                    solu[j][i*2] = a;
                    solu[j][i*2+1] = b;
                    used[j] = 1;
                    if(c<0)  //开始顶点
                        c = a;
                    d = b; 
                    for(k=0; k<n; k++)  //找下一个立方体
                        if(used[k]==0 && (board[k][edge[i*n+k]*2]==b || board[k][edge[i*n+k]*2+1]==b))
                            j = k;
                }while(b != c);  //找了一圈,回到起点
        }while(j<n);  //所有立方体都找遍
    }
    for(j=0; j<n; j++) //立方体的顶面和底面的颜色
    {
        k = 3 - edge[j] - edge[j+n]; 
        a = board[j][k*2];
        b = board[j][k*2+1];
        solu[j][4] = a;
        solu[j][5] = b;
    }
    for(i=0; i<n; i++)
    {
        for(j=0; j<6; j++)
            cout << color[solu[i][j]] << " ";
        cout << endl;
    }
}

void search()
{
    int i, t, cube;
    bool ok, newg, over;
    int *vert = new int[n];  //记录子图中每个顶点的度,应均为2
    int *edge = new int[n*2];  //记录每个立方体中边被选用的条数,每个立方体只有3条边,有两个子图要选用
    for(i=0; i<n; i++)
        vert[i] = 0;
    t = -1;
    newg = true;
    while(t > -2)
    {
        t++;
        cube = t % n;  //每个立方体找2次,得到真实的立方体编号,也是子图中边的编号
        if(newg)  //如果没有边被选入子图
            edge[t] = -1;  
        over = false;  //是否结束,即两个子图构建完成
        ok = false;    //标记边是否已用过,两个子图不应有公共边
        while(!ok && !over)
        {
            edge[t]++;  //边被选用加入子图,使用次数增加
            if(edge[t]>2)  //在立方体每对相对面的顶点连一条边,每个立方体只有3条边
                over = true;
            else
                ok = (t<n || edge[t]!=edge[cube]);  //是否已用过
        }
        if(!over)
        {          //检测边的两个顶点的度
            if(++vert[board[cube][edge[t]*2]] > 2+t/2*2) //如果是第一个子图,顶点度不能超过2
                ok = false;              //如果是第二个子图,加上第一个子图,顶点度不能超过4
            if(++vert[board[cube][edge[t]*2+1]] > 2+t/2*2)
                ok = false;
            if(t%n == n-1 && ok)  //如果一个或两个子图已构建完成
                for(i=0; i<n; i++)
                    if(vert[i] > 2+t/n*2)
                        ok = false;
            if(ok)
            {
                if(t == n*2-1) //找到解
                {
                    ans++;
                    out(edge);
                    return;
                }
                else
                    newg = true;
            }
            else //取下一条边
            {
                --vert[board[cube][edge[t]*2]];  //边的两个顶点
                --vert[board[cube][edge[t]*2+1]];
                t--;
                newg = false;
            }
        }  
        else //回溯
        {
            t--;
            if(t > -1)
            {
                cube = t % n;
                --vert[board[cube][edge[t]*2]];
                --vert[board[cube][edge[t]*2]];
            }
            t--;
            newg = false;
        }
    }
}

int main()
{
    ifstream fin("n色方柱.txt");
    cout << "输入立方体个数:";
    fin >> n;  cout << n;
    cout << "\n输入颜色:";
    for(int i=0; i<n; i++)
    {
        fin >> color[i];
        cout << color[i] << " ";
    }
    cout << "\n输入立方体各面颜色:\n";
    for(i=0; i<n; i++)
    {
        for(int j=0; j<6; j++)
        {
            fin >> board[i][j];
            cout << board[i][j] << " ";
        }
        cout << endl;
    }

    cout << "\n立方体叠置方案为:\n";
    search();
    if(ans == 0)
        cout << "No Solution!\n";
    cout << endl;
    fin.close();
    return;
}

这里写图片描述

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值