• [SDOI2010] 魔法猪学院


    魔法猪学院

    题目背景

    感谢@kczno1 @X_o_r 提供hack数据

    题目描述

    iPig在假期来到了传说中的魔法猪学院,开始为期两个月的魔法猪训练。经过了一周理论知识和一周基本魔法的学习之后,iPig对猪世界的世界本原有了很多的了解:众所周知,世界是由元素构成的;元素与元素之间可以互相转换;能量守恒……。

    能量守恒……iPig 今天就在进行一个麻烦的测验。iPig 在之前的学习中已经知道了很多种元素,并学会了可以转化这些元素的魔法,每种魔法需要消耗 iPig 一定的能量。作为 PKU 的顶尖学猪,让 iPig 用最少的能量完成从一种元素转换到另一种元素……等等,iPig 的魔法导猪可没这么笨!这一次,他给 iPig 带来了很多 1 号元素的样本,要求 iPig 使用学习过的魔法将它们一个个转化为 N 号元素,为了增加难度,要求每份样本的转换过程都不相同。这个看似困难的任务实际上对 iPig 并没有挑战性,因为,他有坚实的后盾……现在的你呀!

    注意,两个元素之间的转化可能有多种魔法,转化是单向的。转化的过程中,可以转化到一个元素(包括开始元素)多次,但是一但转化到目标元素,则一份样本的转化过程结束。iPig 的总能量是有限的,所以最多能够转换的样本数一定是一个有限数。具体请参看样例。

    输入输出格式

    输入格式:

    第一行三个数 N、M、E 表示iPig知道的元素个数(元素从 1 到 N 编号)、iPig已经学会的魔法个数和iPig的总能量。

    后跟 M 行每行三个数 si、ti、ei 表示 iPig 知道一种魔法,消耗 ei 的能量将元素 si 变换到元素 ti 。

    输出格式:

    一行一个数,表示最多可以完成的方式数。输入数据保证至少可以完成一种方式。

    输入输出样例

    输入样例#1:

    4 6 14.9
    1 2 1.5
    2 1 1.5
    1 3 3
    2 3 1.5
    3 4 1.5
    1 4 1.5
    

    输出样例#1:

    3
    

    说明

    有意义的转换方式共4种:

    1->4,消耗能量 1.5

    1->2->1->4,消耗能量 4.5

    1->3->4,消耗能量 4.5

    1->2->3->4,消耗能量 4.5

    显然最多只能完成其中的3种转换方式(选第一种方式,后三种方式仍选两个),即最多可以转换3份样本。

    如果将 E=14.9 改为 E=15,则可以完成以上全部方式,答案变为 4。

    数据规模

    占总分不小于 10% 的数据满足 (N leq 6,M leq 15)

    占总分不小于 20% 的数据满足 (N leq 100,M leq 300,Eleq100) 且E和所有的ei均为整数(可以直接作为整型数字读入).

    所有数据满足(2 leq N leq 5000, 1 leq M leq 200000, 1 leq E leq 10 ^ 7, 1 leq eileq E),(E)和所有的(ei)为实数。

    题解

    K短路模板
    怎么看出来的呢?转换一下思路,题目要求我们尽量把能量全部用完,也就是说我们可以到达n点多次,求最多次数,这就是要我们求出那个k,那么就是一个k短路的板子题了

    那么怎么求k短路呢?博主蒟蒻只会(A*)的求法
    在搜索中我们应该都用到过(A*),它其实就是一个估价函数

    所谓A就是启发式搜索..说白了就是给BFS搜索一个顺序使得搜索更加合理减少无谓的搜索..如何来确定搜索的顺序?..也就是用一个值来表示这个值为f[x]..每次搜索取f[x]最小的拓展...那么这个f[x]=h[x]+g[x]其中这个h[x]就是当前搜索时的代价..如求K段路这个就是前一个点的h[x']+边的长度...而g[x]是一个估价函数..估价函数要小于是对当前点到目标的代价的估计..这个估计必须小于等于实际值~~否则会出错...A的关键也就是构造g[x]..

    如果当前答案+从当前到目标所需要的花费比我们已有的最优解更劣,那么我们没必要继续使用这个答案

    有人会问,这不是搜索的用法吗,怎么放到图论中来呢?

    在求k短路中

    估价函数=当前节点距源点的距离h[x]+当前节点距终点的距离g[x]

    我们知道堆优化dijkstra,就是通过优先队列来完成的,这里也是一样,把h[x]+g[x]丢进一个小根堆,每次找到一个h[x]+g[x]的节点来更新其他节点,因为没有标记数组,所以节点可以重复入队,如果目标节点第一次出队,就代表当前路径是第一短路(最短路),第二次出队就是第二短路,第k次出队就是第k短路

    #include<bits/stdc++.h>
    #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
    using namespace std;
    int read(int &ans) {
        ans=0;int f=1; char i=getchar();
        while(i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}
        while(i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+(i^48),i=getchar();
        return ans*f;
    }
    const int inf=2147483647;
    int n,m,cnt,ans,len;
    double V;
    struct node {
        int to,next;
        double v;
    }e[400010],eg[400010];
    struct Node {
        int id;double g,f;
        bool operator < (const Node &a) const {return a.f<f;}
    };
    int head[5010],Head[5010];
    bool vis[5010];
    double dis[5010];
    priority_queue<Node>Q;
    queue<int>q;
    inline void add(int a,int b,double c) {
        e[++cnt].to=a;e[cnt].next=head[b];e[cnt].v=c;head[b]=cnt;
        eg[++len].to=b;eg[len].next=Head[a];eg[len].v=c;Head[a]=len;
    }
    void spfa() {
        For(i,1,n) dis[i]=inf;
        q.push(1);dis[1]=0;vis[1]=1;
        while(!q.empty()) {
            int u=q.front();q.pop();vis[u]=0;
            for(int i=Head[u];i;i=eg[i].next)
            {
                int to=eg[i].to;
                if(dis[to]>dis[u]+eg[i].v) {
                    dis[to]=dis[u]+eg[i].v;
                    if(!vis[to]) vis[to]=1,q.push(to);
                }
            }
        }
    }
    void Astar() {
        if(dis[n]==inf) return;
        Node tmp;
        tmp.id=n,tmp.g=0,tmp.f=dis[n];
        Q.push(tmp);
        while(!Q.empty()) {
            Node u=Q.top();Q.pop();
            if(u.id==1) {V-=u.g; if(V>=0) ans++; else return;}
            for(int i=head[u.id];i;i=e[i].next) {
                int to=e[i].to;
                tmp.g=u.g+e[i].v;
                tmp.f=tmp.g+dis[to];
                tmp.id=to;
                Q.push(tmp);
            }
        }
    }
    int main()
    {
        int u,v;double z;
        read(n);read(m);scanf("%lf",&V);
        if(V==10000000){//洛谷加了组hack数据,明显超过了数据范围,特判
            printf("2002000
    ");
            return 0;
        }
        For(i,1,m) {
            read(u);read(v);scanf("%lf",&z);
            add(u,v,z);
        }
        spfa();Astar();printf("%d
    ",ans);
    }
    

    博主蒟蒻,随意转载.但必须附上原文链接

    http://www.cnblogs.com/real-l/

  • 相关阅读:
    关于Java的代理模式
    关于Java串行、并行执行——使用Callable多线程
    关于区域表system_district:省市县街道四级地址表
    关于MongoDB在windows下安装
    关于Eureka 服务注册列表显示IP问题研究
    关于开发APP接口版本不兼容的问题
    关于MySQL创建数据库字符集和数据库排序规则的对比选择
    关于MySQL的行转列
    关于MySQL统计一列中不同值的数量方法
    关于Java 8 forEach
  • 原文地址:https://www.cnblogs.com/real-l/p/9495444.html
Copyright © 2020-2023  润新知