Piggy Back

问题描述
Bessie 和她的姐姐 Elsie 在不同的田块吃草, 晚上她们都返回牛棚休息。 作为聪明的奶
牛, 她们想设计一个方案使得步行消耗的能量最少。
Bessie 从一个田块到相邻的田块要耗费 B 个单位的能量, Elsie 从一个田块到相邻的田块
要耗费 E 个单位的能量。 然而当 Bessie 和 Elsie 处于同一个田块时, Bessie 用背驮着 Elsie 一
起走, 从一个田块到相邻的田块要耗费 P 个单位的能量。 如果 P 小于 B+E,则被认为是比较
适用的; 如果 P 非常小, 那么最佳的方案就是尽快使得 Bessie 和 Elsie 在某一田块相遇; 当
然如果 P 非常大, 那么则尽可能使得 Bessie 和 Elsie 分开走。 另一方面, 她们对“背驮式”
很不高兴, 她们不明白为什么这种猪用来驮运的方式会被认为是优秀的方法。
给出 B,E 和 P,帮助她们姐俩找出从牧场到牛棚的花费能量最小的方案。
输入格式
第一行包含 5 个正整数 B,E,P,N 和 M。 N 是牧场中田块的数量(分别编号为 1..N),M 表示田块之间通路条数.Bessie 和 Elsie 一开始分别位于 1 和 2,牛棚位于 N.接下来 M 行, 每行一对整数 U 和 V, 分别表示两个田块之间有通路。 通路连接是双向的, 可以从 1 到 N, 和从 2 到 N, 并且沿途有一系列通路。
输出格式
输出共一行一个整数, 表示从牧场到牛棚的花费能量最小的方案。
输入样例
4 4 5 8 8
1 4
2 3
3 4
4 7
2 5
5 6
6 8
7 8
输出样例
22
样例解释
样例中, Bessie 从 1 到 4, Elsie 从 2 到 3 到 4.然后她们一起从 4 到 7 到 8.
数据规模
对于 40%的数据: 3≤N,M≤6,000;
对于 100%的数据: 3≤B,E,P,N,M≤40,000; 1≤U, V≤N; 且 U≠V;

题面貌似十分复杂,但细想并不是很难。只要枚举每一个点,取min,将Bessie,Elsie
走到这个点的最小能量,加上从这个点到终点的能量。
我们可以用广搜(SPFA),就可以求出1, 2,n到每个点的能量。

//d1[i]表示1到i的距离
//d2[i]表示2到i的距离
//d3[i]表示n到i的距离
for(int i=1;i<=n;i++)
ans=min(ans,d1[i]+d2[i]+d3[i]);

这就是核心伪代码。

表示不想写void,直接程序里写了广搜CtrC CtrV

#include<bits/stdc++.h>
#include<vector>
#define zz 2e9
using namespace std;
long long i,j,k,n,m,tot,ans,u,p,v,e,b,tail,head,t,h,ta,he;
long long  d1[40005],d2[40005],d3[40005],q[100005],q1[100005];
vector<long long> f[40005];
int read(){
    char c;int x;while(c=getchar(),c<'0'||c>'9');x=c-'0';
    while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0';
    return x;
}
int minn(int a,int b){return a<b?a:b;}
int main()
{
    b=read(),e=read(),p=read(),n=read(),m=read();head=0,tail=0;
    for(int i=1;i<=m;i++){
        int x=read(),y=read();
        f[x].push_back(y);
        f[y].push_back(x);
    }
    for(int i=1;i<=n;i++) d1[i]=d2[i]=d3[i]=zz;
    for(int i=0;i<f[1].size();i++){
        q[++tail]=f[1][i];d1[f[1][i]]=b;
    }
    d1[1]=0,d2[2]=0,d3[n]=0;
    while(head<tail){
        head++;
        for(int i=0;i<f[q[head]].size();i++){
            if(d1[q[head]]+b<d1[f[q[head]][i]]){
                d1[f[q[head]][i]]=d1[q[head]]+b;
                q[++tail]=f[q[head]][i];
            }
        }
    }
    h=0;t=0;
    for(int i=0;i<f[2].size();i++){
        q[++t]=f[2][i];d2[f[2][i]]=e;
    }
    while(h<t){
        h++;
        for(int i=0;i<f[q[h]].size();i++){
            if(d2[q[h]]+e<d2[f[q[h]][i]]){
                d2[f[q[h]][i]]=d2[q[h]]+e;
                q[++t]=f[q[h]][i];
            }
        }
    }
    he=0;ta=0;
    d3[n]=0;
    for(int i=0;i<f[n].size();i++){
        q1[++ta]=f[n][i];d3[f[n][i]]=p;
    }
    while(he<ta){
        he++;
        for(int i=0;i<f[q1[he]].size();i++){
            if(d3[q1[he]]+p<d3[f[q1[he]][i]]){
                d3[f[q1[he]][i]]=d3[q1[he]]+p;
                q1[++ta]=f[q1[he]][i];
            }
        }
    }
    d1[1]=0,d2[2]=0,d3[n]=0;
    ans=2147483647;
    for(int i=1;i<=n;i++){
        ans=minn(ans,d1[i]+d2[i]+d3[i]);
    }
    printf("%d",ans);
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值