codeforces 313D Ilya and Roads (区间dp)

题意:

n个洞,m个公司,至少补k个洞,每个公司只能补Li到Ri之间的懂,并且费用是ci。问补至少k个洞的最小费用。

题解:

首先我么要这题要知道任意段区间之间的费用是多少,因为公司的区间是可以重合的,但是重合部分要多计算,那么我们可以用(n^3)的计算出任意段区间的费用。

接着我们就可以dp了,dp[i][j]表示前i个点补了k个洞的最小费用。状态方程和往常非常不同本来是要O(n^4)现在优化了一个地方O(n^3)

dp[i][j] = max{ dp[i-1][j] (表示不补i这个洞), dp[i-k][j-k] + cost[i-k+1][i] } 

注意别爆int


#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<map>
using namespace std;
typedef long long lld;
const int oo=0x3f3f3f3f;
const lld OO=1LL<<61;
const int MOD=1000000007;
#define maxn 305
lld dp[maxn][maxn];
lld cost[maxn][maxn];
/**
dp[i][j] = max{ dp[i-1][j] , dp[i-k][j-k] + cost[i-k+1][i] }
*/
int main()
{
    int n,m,k,l,r,c;
    while(scanf("%d %d %d",&n,&m,&k)!=EOF)
    {
        for(int i=0;i<maxn;i++)
            for(int j=0;j<maxn;j++)
                dp[i][j]=cost[i][j]=OO;
        for(int k=1;k<=m;k++)
        {
            scanf("%d %d %d",&l,&r,&c);
            for(int i=l;i<=r;i++)
                for(int j=i;j<=r;j++)
                    cost[i][j]=min(cost[i][j],(lld)c);
        }
        dp[0][0]=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<=n;j++)
            {
                dp[i][j]=dp[i-1][j];
                for(int k=1;k<=i&&k<=j;k++)
                {
                    dp[i][j]=min(dp[i][j],dp[i-k][j-k]+cost[i-k+1][i]);
                }
            }
        }
        if(dp[n][k]==OO)dp[n][k]=-1;
        printf("%I64d\n",dp[n][k]);
    }
    return 0;
}
/**
10 4 6
7 9 11
6 9 13
7 7 7
3 5 6

10 7 1
3 4 15
8 9 8
5 6 8
9 10 6
1 4 2
1 4 10
8 10 13

10 1 9
5 10 14

*/








你可能感兴趣的:(codeforces 313D Ilya and Roads (区间dp))