bzoj1975 [Sdoi2010]魔法猪学院

iPig在魔法猪学院学习元素转换魔法,通过特定的魔法将1号元素转化为N号元素,每份样本的转换过程需不同。面对能量限制,iPig需找到最优路径以最小能量完成任务。采用A*算法优化搜索过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description


iPig在假期来到了传说中的魔法猪学院,开始为期两个月的魔法猪训练。经过了一周理论知识和一周基本魔法的学习之后,iPig对猪世界的世界本原有了很多的了解:众所周知,世界是由元素构成的;元素与元素之间可以互相转换;能量守恒……。 能量守恒……iPig 今天就在进行一个麻烦的测验。iPig 在之前的学习中已经知道了很多种元素,并学会了可以转化这些元素的魔法,每种魔法需要消耗 iPig 一定的能量。作为 PKU 的顶尖学猪,让 iPig 用最少的能量完成从一种元素转换到另一种元素……等等,iPig 的魔法导猪可没这么笨!这一次,他给 iPig 带来了很多 1 号元素的样本,要求 iPig 使用学习过的魔法将它们一个个转化为 N 号元素,为了增加难度,要求每份样本的转换过程都不相同。这个看似困难的任务实际上对 iPig 并没有挑战性,因为,他有坚实的后盾……现在的你呀! 注意,两个元素之间的转化可能有多种魔法,转化是单向的。转化的过程中,可以转化到一个元素(包括开始元素)多次,但是一但转化到目标元素,则一份样本的转化过程结束。iPig 的总能量是有限的,所以最多能够转换的样本数一定是一个有限数。具体请参看样例。

占总分不小于 10% 的数据满足 N <= 6,M<=15。
占总分不小于 20% 的数据满足 N <= 100,M<=300,E<=100且E和所有的ei均为整数(可以直接作为整型数字读入)。
所有数据满足 2 <= N <= 5000,1 <= M <= 200000,1<=E<=107,1<=ei<=E,E和所有的ei为实数。

Solution


所有的转化方法可以看成是有向边,实际要求的是一个最大整数k使得第1到第k短路的长度和不大于E

这题十分不友好,洛谷上的数据专门卡A*,bzoj的数据专门卡优先队列空间,一开始又十分naïve打了左偏树,凎

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))

const int INF=0x3f3f3f3f;
const int N=50005;
const int E=200005;

struct edge {int x,y; double w; int next;} e[E];
struct data {
    int x; double f,g;
    bool operator <(data b) const {
        return f+g<b.f+b.g;
    }
} val[N];
struct HEAP {
    data val[E*14]; int tot;
    void push(data x) {
        val[++tot]=x;
        for (int i=tot;i>1&&val[i]<val[i/2];i/=2) {
            std:: swap(val[i],val[i/2]);
        }
    }
    data pop() {
        data ret=val[1]; val[1]=val[tot]; tot--;
        for (int i=1;val[i*2]<val[i]&&i*2<=tot||val[i*2+1]<val[i]&&i*2+1<=tot;) {
            if (val[i*2]<val[i*2+1]||i*2+1>tot) {
                std:: swap(val[i],val[i*2]);
                i*=2;
            } else {
                std:: swap(val[i],val[i*2+1]);
                i=i*2+1;
            }
        }
        return ret;
    }
    bool empty() {
        return tot==0;
    }
} heap;

int cnt[N],ls[N],V,edCnt;
int lson[N],rson[N],fa[N];
int queue[N];
double dis[N];

bool vis[N];

void add_edge(int x,int y,double w) {
    e[++edCnt]=(edge) {x,y,w,ls[x]}; ls[x]=edCnt;
}

void spfa(int st,int ed) {
    int head=1,tail=1; queue[tail]=st;
    vis[st]=1;
    rep(i,0,N-1) dis[i]=INF; dis[st]=0;
    while (head<=tail) {
        int now=queue[head++];
        for (int i=ls[now];i;i=e[i].next) {
            if (dis[now]+e[i].w<dis[e[i].y]) {
                dis[e[i].y]=dis[now]+e[i].w;
                if (!vis[e[i].y]) {
                    vis[e[i].y]=1;
                    queue[++tail]=e[i].y;
                }
            }
        }
        vis[now]=0;
    }
}

void A_star(int st,int ed,double lim) {
    heap.push((data) {st,0,dis[st]});
    double tot=0;
    while (!heap.empty()) {
        data top=heap.pop();
        cnt[top.x]++;
        if (top.x==ed) {
            tot+=top.f;
            if (tot>lim) {
                printf("%d\n", cnt[top.x]-1);
                return ;
            }
            continue;
        }
        for (int i=ls[top.x];i;i=e[i].next) {
            heap.push((data) {e[i].y,top.f+e[i].w,dis[e[i].y]});
        }
    }
}

int main(void) {
    int n,m; double lim;
    scanf("%d%d%lf",&n,&m,&lim);
    rep(i,1,m) {    
        int x,y; double w; scanf("%d%d%lf",&x,&y,&w);
        add_edge(y,x,w);
    }
    spfa(n,1);
    fill(ls,0); int tmp=edCnt; edCnt=0;
    rep(i,1,tmp) add_edge(e[i].y,e[i].x,e[i].w);
    A_star(1,n,lim);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值