洛谷 P3125 [USACO15OPEN]Bessie的生日自助餐Bessie's… ( spfa+dp) 题解

94 篇文章 0 订阅
25 篇文章 0 订阅

题目来源:

https://www.luogu.org/problemnew/show/P3125

题目描述:

题目描述

For Bessie the cow’s birthday, Farmer John has given her free reign over one

of his best fields to eat grass.

The field is covered in NN patches of grass (1 \le N \le 10001≤N≤1000), conveniently

numbered 1\ldots N1…N, that each have a distinct quality value. If Bessie eats

grass of quality QQ, she gains QQ units of energy. Each patch is connected to

up to 10 neighboring patches via bi-directional paths, and it takes Bessie EE

units of energy to move between adjacent patches (1 \le E \le 1,000,0001≤E≤1,000,000).

Bessie can choose to start grazing in any patch she wishes, and she wants to

stop grazing once she has accumulated a maximum amount of energy.

Unfortunately, Bessie is a picky bovine, and once she eats grass of a certain

quality, she’ll never eat grass at or below that quality level again! She is

still happy to walk through patches without eating their grass; in fact, she

might find it beneficial to walk through a patch of high-quality grass without

eating it, only to return later for a tasty snack.

Please help determine the maximum amount of energy Bessie can accumulate.

为了庆祝奶牛Bessie的生日,Farmer John给了她一块最好的牧场,让她自由的享用。

牧场上一共有N块草地(1≤N≤1000),编号为1...N,每块草地上牧草的质量都不同。

如果Bessie吃掉的草地上牧草质量为Q,她可以获得Q单位的能量。

每块草地最多和10块草地有相连的道路,在相连的两个草地之间走动需要消耗E单位的能量(1≤E≤1,000,000)。

Bessie可以从任意一块草地开始吃草,并且想要在获得了最多能量的时候停止。

有点遗憾的,Bessie是一头挑食的奶牛,一旦她吃过了一定质量的牧草,她就不会再吃相同或更低质量的牧草!但是她仍然很愿意路过某些草地,而不吃它们。实际上,她发现路过一块高质量的草地而不吃它,等一下返回再去享用,有时会更有利!

请帮忙计算Bessie能够获得的能量的最大值。

输入输出格式

输入格式:

 

The first line of input contains NN and EE. Each of the remaining NN lines

describe a patch of grass. They contain two integers QQ and DD giving the

quality of the patch (in the range 1\ldots 1,000,0001…1,000,000) and its number of

neighbors. The remaining DD numbers on the line specify the neighbors.

1行:包含两个整数N和E。

接下来N行:每行描述一块草地,首先两个整数Q和D,分别表示草地上牧草的质量(范围1…1,000,000)和相连的草地数量。然后D个整数表示相连的草地。

 

输出格式:

 

Please output the maximum amount of energy Bessie can accumulate.

输出Bessie能够获得的能量的最大值。

 

输入输出样例

输入样例#1: 复制

5 2
4 1 2
1 3 1 3 4
6 2 2 5
5 2 2 5
2 2 3 4

输出样例#1: 复制

7

说明

Bessie starts at patch 4 gaining 5 units of energy from the grass there. She

then takes the path to patch 5 losing 2 units of energy during her travel.

She refuses to eat the lower quality grass at patch 5 and travels to patch 3

again losing 2 units of energy. Finally she eats the grass at patch 3 gaining 6 units of energy

for a total of 7 energy.

Note tha the sample case above is different from test case 1 when you submit.

感谢@蒟蒻orz神犇 提供翻译

解题思路:

       这题,一开始看没什么思路,后来看了题解,自己推了,一下才知道dp的状态转移方程,设dp【u】是从u出发获得的最大能量,所以dp【u】=max(dp【u】,dp【v】-dis【v】【u】+w【u】),w【u】为u点的能量,dis【v】【u】是v到u的最短距离,首先我们要求出每个点的最短距离,因为本题是稀疏图,所以我们只要用n次spfa会比较快,因为题目要求质量递增,所以我们可以先排个序,保证w【v】<w【u】,只要就行了,具体细节看代码。。

代码:

#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <queue>
#include <stack>
#include <cmath>
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
const int  maxn=1e5+10;
int n,E,head[1010],cnt=0,vis[1010],dis[1010][1010],dp[1010];
struct newtt
{
    int num,w;
}dian[1010];
bool cmp(newtt a,newtt b)
{
    return a.w<b.w;
}
struct newt
{
    int to,next,cost;
}e[maxn];
void addedge(int u,int v,int w)
{
    e[cnt].to=v;
    e[cnt].next=head[u];
    e[cnt].cost=w;
    head[u]=cnt++;
}
void sfpa(int u)
{
    for(int i=1;i<=n;i++)dis[u][i]=inf,vis[i]=0;
    queue<int>q;
    q.push(u);
    vis[u]=1;
    dis[u][u]=0;
    while(!q.empty())
    {
        int now=q.front();
        q.pop();
        vis[now]=0;
        for(int i=head[now];i!=-1;i=e[i].next)
        {
            int v=e[i].to;
            if(dis[u][v]>dis[u][now]+e[i].cost)
            {
                dis[u][v]=dis[u][now]+e[i].cost;
                if(vis[v])continue;
                q.push(v);
                vis[v]=1;
            }
        }
    }
}
int main()
{
    scanf("%d%d",&n,&E);
    for(int i=1;i<=n;i++)head[i]=-1;
    for(int i=1,m;i<=n;i++)
    {
        scanf("%d",&dian[i].w);
        dp[i]=dian[i].w;
        dian[i].num=i;
        scanf("%d",&m);
        for(int j=1,x;j<=m;j++)
        scanf("%d",&x),addedge(i,x,E);
    }
    sort(dian+1,dian+n+1,cmp);
    for(int i=1;i<=n;i++)sfpa(i);
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<i;j++)
        {
            
            int u=dian[i].num,v=dian[j].num;
        //	printf("%d\n",dis[v][u]);
            dp[u]=max(dp[u],dp[v]-dis[v][u]+dian[i].w);
        }
        ans=max(ans,dp[dian[i].num]);
        //printf("%d %d\n",dian[i].num,dp[dian[i].num]);
    }
    printf("%d\n",ans);
    return 0;
}

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值