1. 程式人生 > >[K短路] SDOI2010 魔法豬學院

[K短路] SDOI2010 魔法豬學院

一周 log bfs搜索 names 三種方式 學會 轉載 範圍 重復

魔法豬學院

題目背景

感謝@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 魔法豬學院