着色方案——dp

考虑不同次数有多少个
不要考虑不同颜色有多少个

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int cnt[6];// 表示 可以使用i次的 颜色有多少个
ll vis[16][16][16][16][16][16];
int k;
const int mod = 1e9+7;

ll dfs(int t1, int t2, int t3, int t4, int t5, int last)
{
    ll ans = 0;
    if(t1+t2+t3+t4+t5 == 0)return 1;

    if(vis[t1][t2][t3][t4][t5][last]!= 0)return vis[t1][t2][t3][t4][t5][last];

    if(t1)//如果使用的1次的还存在
    {
        ans+=(t1- (last == 2))*dfs(t1-1, t2, t3, t4, t5, 1);/******last == 2 的 作用: 如果上次是使用2次的,这次就变成了使用1次的了, 因为不能连续图相同的颜色,所以那个1次要减去******************/
        ans%=mod;
    }

    if(t2)
    {
        ans+=(t2 - (last == 3))*dfs(t1+1, t2-1, t3 ,t4, t5, 2);// 为甚么 要+1 -1, 这次使用颜色是2 次的 , 所以 那个颜色在下一个状态 只能使用一次了, 所以要+1, -1. 
        ans%=mod;
    }

    if(t3)
    {
        ans+=(t3- (last == 4))*dfs(t1,  t2+1, t3-1, t4, t5, 3);
        ans%=mod;
    }

    if(t4)
    {
        ans+=(t4- (last == 5))*dfs(t1, t2, t3+1, t4-1, t5, 4);
        ans%=mod;
    }

    if(t5)
    {
        ans+=t5*dfs(t1, t2, t3, t4+1, t5-1, 5);
        ans%=mod;
    }


    return vis[t1][t2][t3][t4][t5][last] =ans;
}
int main()
{

    memset(cnt, 0, sizeof(cnt));
    memset(vis, 0, sizeof(vis));
    scanf("%d", &k);

    for(int i = 0;i < k;i++)
    {
        int c;
        scanf("%d", &c);
        cnt[c]++;
    }

    ll ans = dfs(cnt[1], cnt[2], cnt[3], cnt[4], cnt[5], 0);

    printf("%lld", ans);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
邻接矩阵是一种用于表示无向图的矩阵结构,其中矩阵的行和列均代表图中的顶点,如果两个顶点之间有边相连,则对应的矩阵元素为1,否则为0。在这个问题中,我们需要判断给定的无向图是否能够用3种颜色进行着色,具体方法如下: 1. 读入邻接矩阵 我们首先需要读入给定的无向图的邻接矩阵,假设矩阵的大小为V * V,其中V为顶点数。可以使用二维数组来表示邻接矩阵,例如: ``` int G[MAXV][MAXV]; // 图的邻接矩阵表示 int V; // 图的顶点数 // 读入图的顶点数和邻接矩阵 scanf("%d", &V); for (int i = 0; i < V; i++) { for (int j = 0; j < V; j++) { scanf("%d", &G[i][j]); } } ``` 2. 检查相邻顶点的颜色是否相同 在进行图的着色时,我们需要保证相邻的顶点颜色不同。因此,对于每个顶点v,需要检查与之相邻的所有顶点的颜色是否与v的颜色相同。如果相同,则说明这个顶点不能着当前的颜色。 ``` bool is_valid(int v, int c) { for (int i = 0; i < V; i++) { if (G[v][i] && color[i] == c) { return false; } } return true; } ``` 这个函数接受两个参数,分别是当前顶点的编号v和当前尝试的颜色c。它遍历与v相邻的所有顶点i,如果i与v相邻且颜色相同,则返回false,否则返回true。 3. 尝试给每个顶点着色着色时,我们可以使用回溯法来尝试给每个顶点着色。具体来说,我们从第一个顶点开始,依次尝试用三种颜色中的一种进行着色,如果当前的着色方案合法,则继续对下一个顶点进行着色。如果所有顶点都已经着色,则说明找到了一种合法的着色方案。 ``` bool backtrack(int v) { // 如果所有顶点都已经着色,返回true if (v == V) { return true; } // 尝试给当前顶点着色 for (int c = 1; c <= MAXC; c++) { if (is_valid(v, c)) { color[v] = c; // 继续给下一个顶点着色 if (backtrack(v + 1)) { return true; } // 如果不能继续给下一个顶点着色,回溯 color[v] = 0; } } // 如果无法给当前顶点着色,返回false return false; } ``` 这个函数接受一个参数v,表示当前需要进行着色的顶点编号。它首先检查是否所有顶点都已经着色,如果是,则返回true。否则,它尝试给当前顶点着三种颜色中的一种,检查是否合法,如果合法,则继续对下一个顶点进行着色;否则,回溯到上一个顶点,重新尝试其他颜色。 4. 输出着色方案 如果找到了一种合法的着色方案,则输出这个方案。否则,说明这个图不能用三种颜色进行着色满足相邻顶点颜色互异的要求。 ``` // 尝试给每个顶点着色,如果成功则输出着色方案 if (backtrack(0)) { printf("Yes\n"); for (int i = 0; i < V; i++) { printf("%d ", color[i]); } printf("\n"); } else { printf("No\n"); } ``` 这段代码调用backtrack函数,并根据返回值判断是否找到了合法的着色方案。如果找到了,输出"YES",并输出每个顶点的颜色编号;否则,输出"NO"。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值