牛牛的宝可梦Go(dp+floyd)

题目链接:传送门

来源:牛客网

题目描述
牛牛所在的W市是一个不太大的城市,城市有n个路口以及m条公路,这些双向连通的公路长度均为1,保证你可以从一个城市直接或者间接移动到所有的城市。牛牛在玩宝可梦Go,众所周知呢,这个游戏需要到城市的各个地方去抓宝可梦,假设现在牛牛知道了接下来将会刷出k只宝可梦,他还知道每只宝可梦的刷新时刻、地点以及该宝可梦的战斗力,如果在宝可梦刷新时,牛牛恰好在那个路口,他就一定能够抓住那只宝可梦。

由于游戏公司不想让有选择恐惧症的玩家为难,所以他们设计不存在任何一个时刻同时刷出两只及以上的宝可梦。

假设不存在任何一个时刻会同时刷出两只宝可梦,牛牛一开始在城市的1号路口,最开始的时刻为0时刻,牛牛可以在每个时刻之前移动到相邻他所在位置的路口,当然他也可以保持原地不动,他现在想知道他能够捕获的宝可梦战斗力之和最大为多少?

输入描述:
第一行输入两个正整数n,m,(1 \leq n \leq 200,0 \leq m \leq 10000)(1≤n≤200,0≤m≤10000)表示城市的路口数目以及公路数目。

接下来m行每行两个正整数u,v(1 \leq u,v \leq n)(1≤u,v≤n)表示一条长度为1链接两个路的公路。

接下来一行输入一个正整数k(1 \leq k \leq 10^5)(1≤k≤10
5
)表示宝可梦的数目。

接下来输入k行,每行三个正整数t_i,p_i,val_i(1 \leq p_i \leq n,1 \leq t_i,val_i \leq 10^9)t
i

,p
i

,val
i

(1≤p
i

≤n,1≤t
i

,val
i

≤10
9
),分别表示宝可梦刷新的时间、地点、以及战斗力,输入数据保证不会出现在同一时刻刷出多只宝可梦。

输出描述:
输出一个整数表示牛牛能捉到的宝可梦战斗力之和最大是多少。

示例1
输入
3 2
1 2
2 3
3
1 1 5
2 3 10
3 2 1
输出
11

示例2
输入
1 0
3
1 1 100
100 1 10000
10000 1 1
输出
10101

思路:floyd+01背包,要到宝可梦所在的地点,只能从最多200个点转移过来,也就是说,如果两个宝可梦的时间差距超过200,能从任意点转移过来,那么对于每一个宝可梦向下枚举200个就可以了。(我做的时候前面没问题,dp的时候出现了问题,,)

代码

#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int N = 205,M=1e5+10,mod=1e9+7;
typedef long long ll;
#define inf 0x3f3f3f3f
int mp[N][N];
int n,m;
struct node
{
    int t,pos,v;
}a[M],b[M];
ll dp[M];
void Floyd()
{
    for(int k=1;k<=n;k++)
    {
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
    }
}
bool cmp(node x,node y)
{
    if(x.t==y.t)
        return x.v>y.v;
    return x.t<y.t;
}
int main()
{
    int k;
    cin>>n>>m;
    memset(mp,inf,sizeof mp);
    for(int i=1;i<=n;i++) mp[i][i]=0;
    for(int i=0;i<m;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        mp[a][b]=mp[b][a]=1;
    }
    Floyd();
    cin>>k;
    for(int i=1;i<=k;i++)
    {
        int t,pos,v;
        scanf("%d%d%d",&t,&pos,&v);
        a[i]={t,pos,v};
    }
    a[0]={0,1,0};
    ll ans=0,nowmax=0;
    sort(a+1,a+k+1,cmp);
    for(int i=1;i<=k;i++)
    {
        dp[i]=-inf;
        for(int j=1;j<=200&&i-j>=0;j++)
        {
            if(a[i].t-a[i-j].t>=mp[a[i].pos][a[i-j].pos])
                dp[i]=max(dp[i],dp[i-j]+a[i].v);
        }
        ans=max(ans,dp[i]);
    }
    cout<<ans<<endl;
    return 0;
}


你可能感兴趣的:(dp)