看上去就是DP的一个题,由于自己太菜了,还是不会做

先给个提交的地方:cf 711C


这个题看到数据,很明显是dp,因为n,m,k的值都不大,我们可以建立矩阵来推理

很明显答案跟dp【n】【k】有关


也就是dp【i】【j】代表前i个树涂完之后,有了j个匹配的最小花费

但是,这样怎么转移呢?!

很明显,数组还可以再开得大一点,多加一维(又相当于多了一个分层图)

dp【i】【j】代表前i个树涂完之后,有了j个匹配,最后一棵树(第i颗树)的颜色为k,的最小花费


那么初始值:

看第一课树是不是染色已经染好了

如果a【i】=0,那么就是需要染色

那么就需要枚举第三维的K,给一个初值

如果a【i】!=0,那么就是不需要染色

那么,那就是dp【1】【1】【a【i】】=0

其他的都是不合法状态


然后状态转移也是根据a【i】是否染色来判断

枚举i,j,k,然后去暴力的计算每个状态量的值

多一维变量枚举,就是说明,如果我想涂的颜色和当前最后一个一样,那么我就需要把美丽度+1

否则是不变的

注意好转移的细节就好


#include<bits/stdc++.h>
using namespace std;

#define LL __int64
LL dp[110][110][110];
LL p[200][200];
int a[200];
const LL INF=0x3f3f3f3f3f3f3f3f3f;

int main(){
    //freopen("input.txt","r",stdin);
    int n,m,k;
    while(scanf("%d%d%d",&n,&m,&k)!=EOF){
        //printf("%d %d %d\n",n,m,k);
        memset(dp,0x3f3f3f3f,sizeof(dp));
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%I64d",&p[i][j]);
        if (a[1]) dp[1][1][a[1]]=0;
        else{
            for(int c=1;c<=m;c++)
                dp[1][1][c]=p[1][c];
        }
        for(int i=2;i<=n;i++)
        if (a[i]==0){
            for(int x=1;x<i;x++)
            for(int c=1;c<=m;c++)
            for(int l=1;l<=m;l++)
                if (l!=c)
                    dp[i][x+1][c]=min(dp[i][x+1][c],dp[i-1][x][l]+p[i][c]);
                else
                    dp[i][x][c]=min(dp[i][x][c],dp[i-1][x][l]+p[i][c]);
        }
        else{
            for(int x=1;x<i;x++)
            for(int l=1;l<=m;l++)
                if (l!=a[i])
                    dp[i][x+1][a[i]]=min(dp[i][x+1][a[i]],dp[i-1][x][l]);
                else
                    dp[i][x][a[i]]=min(dp[i][x][a[i]],dp[i-1][x][l]);
        }
        LL ans=INF;
        for(int c=1;c<=m;c++)
            ans=min(ans,dp[n][k][c]);
        if (ans==INF) ans=-1;
        cout<<ans<<endl;
    }
    return 0;
}