1. 程式人生 > 實用技巧 >POJ-1018 Communication System(dp)

POJ-1018 Communication System(dp)

題目描述

  有 \(n(1\leq n \leq 100)\) 種裝置,每種裝置有 \(c_i(1\leq c_i\leq 100)\) 個廠家生產,裝置 \(i(1\leq i\leq n)\) 的第 \(j(1\leq j\leq c_i)\) 個廠家生產的裝置會存在兩個方面的差別:引數 \(a_{ij}\) 和價格 \(b_{ij}\)

  現在每種裝置都需要 \(1\) 個,設 \(\min\) 為選出的 \(n\) 件裝置中的最小引數,\(\text{sum}\) 為選出的 \(n\) 件裝置的總價格,求 \(\frac{\min}{\text{sum}}\) 的最大值。

分析

  設 \(dp[i][j]\)

為對於前 \(i\) 件物品,引數最小值為 \(j\) 的價格總和;對於前 \(i-1\) 件物品,設引數的最小值為 \(k\)

  當 \(j\leq k\) 時,\(dp[i][j]=\min(dp[i][j],dp[i-1][k]+b_{ij})\)

  當 \(j>k\) 時,\(dp[i][k]=\min(dp[i][k],dp[i-1][k]+b_{ij})\)

  轉移的時候從 \(0\) ~ \(2000\) 列舉最小引數 \(j\);最後求答案的時候,列舉 \(i\in[0,2000]\),求 \(i/dp[n][i]\) 的最大值。

程式碼

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int c[110],a[110][110],b[110][110];
int dp[120][2010];
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        memset(dp,0x3f,sizeof(dp));
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&c[i]);
            for(int j=1;j<=c[i];j++)
                scanf("%d %d",&a[i][j],&b[i][j]);
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=c[i];j++)
            {
                if(i==1)
                    dp[1][a[1][j]]=min(dp[1][a[1][j]],b[1][j]);
                else
                {
                    for(int k=0;k<=2000;k++)
                    {
                        if(dp[i-1][k]!=0x3f)
                        {
                            if(a[i][j]<=k)
                                dp[i][a[i][j]]=min(dp[i][a[i][j]],dp[i-1][k]+b[i][j]);
                            else
                                dp[i][k]=min(dp[i][k],dp[i-1][k]+b[i][j]);
                        }
                    }
                }
            }
        }
        double ans=0.0;
        for(int i=0;i<=2000;i++)
            if(dp[n][i]!=0x3f)
                ans=max(ans,1.0*i/dp[n][i]);
        printf("%.3f\n",ans);
    }
    return 0;
}