[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/

原文地址:https://www.cnblogs.com/real-l/p/9495444.html