【bzoj1975】[Sdoi2010]魔法豬學院

*題目描述:
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 。
*輸出:
一行一個數,表示最多可以完成的方式數。輸入數據保證至少可以完成一種方式。
*樣例輸入:
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
*樣例輸出:
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 <= 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爲實數。
*來源:
Sdoi2010 Contest2 Day2
*題解:
k短路。具體做法是SPFA+A*。先從匯點開始跑一遍SPFA,算出從匯點到達每個點的最短路程。然後再正着跑一遍搜索,搜索的隊列爲以當前源點到這個點的距離和預計到達匯點距離之和爲優先級的優先隊列。此時,每一次到達匯點的路徑則爲當前除了已經找到的路徑之外的最短路,所以只要重複找到k次即可。這題求的是前綴和小於某個數的k的數量。同理即可。
*代碼:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>

#ifdef WIN32
    #define LL "%I64d"
#else
    #define LL "%lld"
#endif

#ifdef CT
    #define debug(...) printf(__VA_ARGS__)
    #define setfile() 
#else
    #define debug(...)
    #define filename ""
    #define setfile() freopen(filename".in", "r", stdin); freopen(filename".out", "w", stdout);
#endif

#define R register
#define getc() (S == T && (T = (S = B) + fread(B, 1, 1 << 15, stdin), S == T) ? EOF : *S++)
#define dmax(_a, _b) ((_a) > (_b) ? (_a) : (_b))
#define dmin(_a, _b) ((_a) < (_b) ? (_a) : (_b))
#define cmax(_a, _b) (_a < (_b) ? _a = (_b) : 0)
#define cmin(_a, _b) (_a > (_b) ? _a = (_b) : 0)
char B[1 << 15], *S = B, *T = B;
inline int FastIn()
{
    R char ch; R int cnt = 0; R bool minus = 0;
    while (ch = getc(), (ch < '0' || ch > '9') && ch != '-') ;
    ch == '-' ? minus = 1 : cnt = ch - '0';
    while (ch = getc(), ch >= '0' && ch <= '9') cnt = cnt * 10 + ch - '0';
    return minus ? -cnt : cnt;
}
#define maxn 5010
#define maxm 400010
struct Edge
{
    int to;
    double w;
    Edge *next;
}*last[maxn], e[maxm], *ecnt = e, *last2[maxn];
std::queue<int> q;
struct astar
{
    int pos;
    double val;
};
double d[maxn];
inline bool operator < (const astar &i, const astar &j) {return i.val + d[i.pos] > j.val + d[j.pos]; }
std::priority_queue<astar> hp;
bool vis[maxn];
int main()
{
//  setfile();
    R int n, m; R double tot;
    scanf("%d%d%lf", &n, &m, &tot);
    for (R int i = 1; i <= m; ++i)
    {
        R int a, b; R double v;
        scanf("%d%d%lf", &a, &b, &v);
        *++ecnt = (Edge) {b, v, last[a]}; last[a] = ecnt;
        *++ecnt = (Edge) {a, v, last2[b]}; last2[b] = ecnt;
    }
    q.push(n);
    for (R int i = 1; i < n; ++i) d[i] = 1.0 / 0.0;
    while (!q.empty())
    {
        R int now = q.front(); q.pop(); vis[now] = 0;
        for (R Edge *iter = last2[now]; iter; iter = iter -> next)
        {
            R int pre = iter -> to;
            if (d[now] + iter -> w < d[pre])
            {
                d[pre] = d[now] + iter -> w;
                if (!vis[pre])
                {
                    q.push(pre);
                    vis[pre] = 1;
                }
            }
        }
    }
    hp.push((astar){1, 0.0});
    R int ans = 0; R double cnt = 0.0;
    while (!hp.empty())
    {
        R astar now = hp.top(); hp.pop();
        if (now.pos == n)
        {
            ++ans; cnt += now.val;
            if (cnt > tot) return !printf("%d\n", ans - 1 );
        }
        else
            for (R Edge *iter = last[now.pos]; iter; iter = iter -> next)
                hp.push((astar){iter -> to, iter -> w + now.val});
    }
    return 0;
}
/*
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
*/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章