VIJOI 1243 生产产品 前5个点错

两份代码

第一份只能过后5个点

第二份能过全部点

原因是dp更新的时候弄错了。

hack数据:

5 2 1 1

1 1 1 1 1

5 5 5 5 5

正确答案 17

错误答案 13

总结,dp[i][j]要全部更新完之后,再去更新单调队列,否则会将其他人做的第i位的答案拿去更新自己的第i位的答案,这样是不对的。

第一份代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
int n,m,K,l,T[100005][5],dp[100005][5],que[5][5][100005],st[5][5],ed[5][5],f[5][5][100005];
inline void push(int i,int j,int v,int p) {
    while (st[i][j]<=ed[i][j]&&v<f[i][j][ed[i][j]])
        --ed[i][j];
    que[i][j][++ed[i][j]]=p;
    f[i][j][ed[i][j]]=v;
}
inline int getMin(int p,int i,int j,int l) {
    while (st[i][j]<=ed[i][j]&&que[i][j][st[i][j]]+l<p)
        ++st[i][j];
    return f[i][j][st[i][j]];
}
int main()
{
    scanf("%d%d%d%d",&m,&n,&K,&l);
    for (int i=0;i<n;++i)
        for (int j=1;j<=m;++j) {
            scanf("%d",&T[j][i]);
            T[j][i]+=T[j-1][i];
        }
    memset(dp,0x3f,sizeof dp);
    for (int i=0;i<n;++i)
        for (int j=0;j<n;++j)
            if (i!=j)
                push(i,j,-K,0);
    for (int i=1;i<=m;++i) {
        for (int j=0;j<n;++j) {
            for (int k=0;k<n;++k)
                if (k!=j)
                    dp[i][j]=min(dp[i][j],getMin(i,k,j,l)+K+T[i][j]);
            for (int k=0;k<n;++k)
                if (k!=j)
                    push(j,k,dp[i][j]-T[i][k],i);
        }
    }
    int res=inf;
    for (int i=0;i<n;++i)
        res=min(res,dp[m][i]);
    printf("%d\n",res);
    return 0;
}

第二份代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
int n,m,K,l,T[100005][5],dp[100005][5],que[5][5][100005],st[5][5],ed[5][5],f[5][5][100005];
inline void push(int i,int j,int v,int p) {
    while (st[i][j]<=ed[i][j]&&v<f[i][j][ed[i][j]])
        --ed[i][j];
    que[i][j][++ed[i][j]]=p;
    f[i][j][ed[i][j]]=v;
}
inline int getMin(int p,int i,int j,int l) {
    while (st[i][j]<=ed[i][j]&&que[i][j][st[i][j]]+l<p)
        ++st[i][j];
    return f[i][j][st[i][j]];
}
int main()
{
    scanf("%d%d%d%d",&m,&n,&K,&l);
    for (int i=0;i<n;++i)
        for (int j=1;j<=m;++j) {
            scanf("%d",&T[j][i]);
            T[j][i]+=T[j-1][i];
        }
    memset(dp,0x3f,sizeof dp);
    for (int i=0;i<n;++i)
        for (int j=0;j<n;++j)
            if (i!=j)
                push(i,j,-K,0);
    for (int i=1;i<=m;++i) {
        for (int j=0;j<n;++j)
            for (int k=0;k<n;++k)
                if (k!=j)
                    dp[i][j]=min(dp[i][j],getMin(i,k,j,l)+K+T[i][j]);
        for (int j=0;j<n;++j)
            for (int k=0;k<n;++k)
                if (k!=j)
                    push(j,k,dp[i][j]-T[i][k],i);
    }
    int res=inf;
    for (int i=0;i<n;++i)
        res=min(res,dp[m][i]);
    printf("%d\n",res);
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值