[K短路] 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,E\leq100\) 且E和所有的ei均為整數(可以直接作為整型數字讀入).
所有數據滿足\(2 \leq N \leq 5000, 1 \leq M \leq 200000, 1 \leq E \leq 10 ^ 7, 1 \leq ei\leq 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\n");
return 0;
}
For(i,1,m) {
read(u);read(v);scanf("%lf",&z);
add(u,v,z);
}
spfa();Astar();printf("%d\n",ans);
}
博主蒟蒻,隨意轉載.但必須附上原文鏈接
http://www.cnblogs.com/real-l/
[K短路] SDOI2010 魔法豬學院