2020牛客寒假算法基礎集訓營3 J-牛牛的寶可夢Go - floyd最短路+類LIS DP

題目鏈接:https://ac.nowcoder.com/acm/contest/3004/J
題目大意:
在這裏插入圖片描述
在這裏插入圖片描述
我們可以很容易得到一個K^2的算法。因爲每個時間都不同。那麼按時間排序。就是一個LIS。如果滿足(j->i)時間差>=dis(i, j)那麼就可以轉移。
f[i]:if[i]:在捉完第i只寶可夢獲得的最大戰鬥力
f[i]=max(f[i]f[j]+a[i].v)j<i,a[i].ta[j].t>=dis(i,j)f[i]=max(f[i],f[j]+a[i].v) \quad j<i,a[i].t-a[j].t>=dis(i, j)
這裏k太大。k^2肯定是不可以的。但是如果:
a[i].ta[j].t>=200f[i]=max(f[i],f[j])a[i].t-a[j].t>=200。那麼f[i]=max(f[i], f[j])
因爲:這個時候一定滿足a[i].ta[j].t>=dis(i,j)a[i].t-a[j].t>=dis(i, j)
最多200個點。那麼dis(i,j)<=200dis(i, j)<=200
所以轉移方程:
{f[i]=max(f[i]f[j]+a[i].v)j>i-200,a[i].t-a[j].t>=dis(i, j) f[i]=max(f[i]f[j]+a[i].v)j<i-200\begin{cases} f[i]=max(f[i],f[j]+a[i].v) & \text{j>i-200,a[i].t-a[j].t>=dis(i, j) } \\ f[i]=max(f[i],f[j]+a[i].v) & \text{j<i-200} \end{cases}
第一部分暴力轉移。第二部分前綴最大值。所以複雜度爲O(200*k)。

注意要把f[]的初始值設-1.表示這個狀態不能到達。並不是每個寶可夢都是可以捉到的。例如:
3
1 2
2 3
1
1 3

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const LL maxn=205;

LL n, m;
LL e[maxn][maxn];
LL f[100005];
struct node{
    LL t, p;
    LL v;
}a[100005];

int cmp(node &a, node &b){
    return a.t<b.t;
}

void floyd(){
    for(LL k=1;k<=n;k++){
        for(LL i=1;i<=n;i++){
            for(LL j=1;j<=n;j++){
                e[i][j]=min(e[i][j], e[i][k]+e[k][j]);
            }
        }
    }
}

int main()
{
    LL k, x, y, z;
    scanf("%lld%lld", &n, &m);
    for(int i=1; i<=n; i++){
        for(int j=1; j<=n; j++){
            if(i==j) e[i][j]=0;
            else e[i][j]=(1ll<<60);
        }
    }
    for(LL i=1;i<=m;i++){
        scanf("%lld%lld",&x,&y);
        e[x][y]=e[y][x]=1;
    }
    floyd();
    scanf("%lld", &k);
    for(LL i=1; i<=k; i++){
        scanf("%lld%lld%lld", &a[i].t, &a[i].p, &a[i].v);
    }
    sort(a+1, a+k+1, cmp);
    memset(f, -1,sizeof(f));
    a[0].p=1; f[0]=0;
    LL Max=0;
    for(LL i=1; i<=k; i++){
        for(LL j=1; j<200&&j<=k; j++){
            if(i-j>=0&&a[i].t-a[i-j].t>=e[a[i].p][a[i-j].p]&&f[i-j]!=-1){//f[i-j]!=-1 f[i-j]這個狀態一定存在
                f[i]=max(f[i], f[i-j]+a[i].v);
            }
        }
        if(i>=200){
            f[i]=max(f[i], f[i-200]+a[i].v);
            f[i-199]=max(f[i-200], f[i-199]);
        }
        Max=max(Max, f[i]);
    }
    printf("%lld\n", Max);

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章