Codeforces #369 (Div. 2) C. Coloring Trees (3维dp

http://codeforces.com/group/1EzrFFyOc0/contest/711/problem/C

https://blog.csdn.net/qq_36368339/article/details/78568585?locationNum=6&fps=1  题解

题意:(真难理解)有n个点,m种颜色,你要给n个点上没有颜色的点染色。每个点i对应染的颜色j有一个颜料消耗,p[i][j]是点i染成j颜色的花费,你必须保证有k段颜色的点,输出最少花费多少颜料。 


思路:题意稍微不太好理解。。。 
dp[i][j][v]:位置i染第j种颜料恰好有v段颜色,所花费的颜料数量; 
第i个位置没被染色:i已经确定,但j,v未知,需要暴力枚举。 
第i个位置已被染色:i,j已经确定,只需要暴力枚举v。(具体方程看代码)
 
坑点就是初始化,还有注意找最小值。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include <cctype>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<cmath>
 7 #include<string>
 8 #include<cmath>
 9 #include<set>
10 #include<vector>
11 #include<stack>
12 #include<queue>
13 #include<map>
14 using namespace std;
15 #define ll long long
16 #define mem(a,x) memset(a,x,sizeof(a))
17 #define se second
18 #define fi first
19 const int INF= 0x3f3f3f3f;
20 const int N=1e6+5;
21 
22 ll n,m,k,a[105],p[105][105],dp[105][105][105];
23 
24 int main()
25 {
26     cin>>n>>m>>k;
27     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
28     for(int i=1;i<=n;i++)
29         for(int j=1;j<=m;j++) scanf("%d",&p[i][j]);
30 
31     for(int i=1;i<=n;i++)
32         for(int u=1;u<=m;u++)
33         for(int v=1;v<=k;v++) dp[i][u][v]=1e18;
34 
35     if(a[1]==0){ //初始化 如果第一个点没被涂色
36         for(int i=1;i<=m;i++)
37             dp[1][i][1]=p[1][i];  //涂上第一个点对应的p[1][j] ,此时v=1
38     }
39     else{ //第一个点被涂色了
40         dp[1][a[1]][1]=0; //=0 ,因为这样的点 不计入结果
41     }
42 
43     for(int i=2;i<=n;i++)
44     {
45         if(a[i]==0)
46         {
47             for(int u=1;u<=m;u++)
48             {
49                 for(int v=1;v<=k;v++)
50                 {
51                     //下面比较v不变的时候:
52                     dp[i][u][v]=min(dp[i][u][v], dp[i-1][u][v]+p[i][u] );
53 
54                     //下面比较v 变的时候:
55                     for(int j=1;j<=m;j++)
56                     {
57                         if(j!=u && v>1)
58                             dp[i][u][v]=min(dp[i][u][v],dp[i-1][j][v-1]+p[i][u] );
59                     }
60                     //通过以上 找出:对相同的i,在u在[1,m]和v在[1,k]范围内dp[i][u][v]的最小值
61                 }
62             }
63         }
64         else{
65             for(int u=1;u<=m;u++)
66             {
67                 for(int v=1;v<=k;v++)
68                 {
69                     dp[i][a[i]][v]=min(dp[i][a[i]][v],dp[i-1][a[i]][v]);
70                     for(int j=1;j<=m;j++)
71                     {
72                         if(j!=a[i] && v>1)
73                             dp[i][a[i]][v]=min(dp[i][a[i]][v],dp[i-1][j][v-1]);
74                     }
75                 }
76             }
77         }
78     }
79     ll ans=1e18;
80     for(int i=1;i<=m;i++)
81         ans=min(ans,dp[n][i][k]);
82     if(ans==1e18) cout<<-1;
83     else cout<<ans<<endl;
84 }
原文地址:https://www.cnblogs.com/thunder-110/p/9408321.html