1. 程式人生 > >計蒜客成仙之路

計蒜客成仙之路

問題描述

有個蘑菇精想要成仙,但是他必須要收集10000個精靈寶石,不過他要是有花精靈的淚水,就只要8000個精靈寶石就可以了,或者如果他有花精靈的血滴,就只要5000個精靈寶石便可以成仙了。蘑菇精可以和森林裡的其他精靈交換東西,但是修為等級差距過大的交換會影響修煉蘑菇精就跑到花精靈那裡,向他索要淚水或血滴,花精靈要他用精靈寶石來換,或者替他弄來其他的東西,他可以降低價格。蘑菇精於是又跑到其他地方,其他精靈也提出了類似的要求,或者直接用精靈寶石換,或者找到其他東西就可以降低價格。不過蘑菇精沒必要用多樣東西去換一樣東西,因為這不會得到更低的價格。蘑菇精現在很需要你的幫忙,讓他用最少的精靈寶石幫助他成仙。另外他要告訴你的是,在這 個森林裡,交換東西,修為差距超過一定限制的兩個精靈之間不會進行任何形式的直接接觸,包括交易,否則會影響修煉。蘑菇精是外來精靈,所以可以不受這些限制。但是如果他和某個修為等級較低的精靈進行了交易,修為等級較高的的精靈有可能不會再和他交易,他們認為這樣等於是間接接觸,反過來也一樣。因此你需要在考慮所有的情況以後給他提供一個最好的方案。 
為了方便起見,我們把所有的物品從開始進行編號,成仙也看作一個物品,並且編號總是1。每個物品都有對應的代價 P,主人精靈的修為等級L ,以及一系列的替代品Ti和該替代品所對應的“優惠”Vi 。如果兩個精靈脩為等級差距超過了M ,就不能“間接交易”。你必須根據這些資料來計算出蘑菇精最少需要多少精靈寶石才能成仙。 
輸入格式


第一行是兩個整數 ,依次表示修為等級差距限制和M,N(1< =M< =20,1< =N< =20000)物品的總數。接下來按照編號從小到大依次給出了N個物品的描述。每個物品的描述開頭是P,L,X三個非負整數 ( X< N),依次表示該物品的代價、主人精靈的修為等級和替代品總數。接下來X 行每行包括兩個整數T 和V ,分別表示替代品的編號和“優惠價格”。(Σx< =200000) 
輸出格式 
對於每個測試資料,在單獨一行內輸出最少需要的精靈寶石數。 
樣例輸入 
1 4 
10000 3 2 
2 8000 
3 5000 
1000 2 1 
4 200 
3000 2 1 
4 200 
50 2 0 
樣例輸出 
5250

思路:

方案一:我們在一個物品及其優惠商品間增加一條路徑,該路徑的值為負,即其優惠價格。同時我們給每個節點都設定一個權值,即其代價,達到此點時需要消耗這樣的代價。這樣,每個點到根節點的路徑長度,實際上就是經過一系列轉換後(最後一次轉換是獲得此節點)所需要的寶石。這樣,我們求出每個點到根節點的最短路,再找出其中最短的一條最短路,就是答案了。

方案二:新建一個點0,表示什麼都還沒有,也就是起點,每一個物品作為一個點,到了這個點表示我當前手上拿的就是這個物品,0向其它的點連邊,邊權為物品本身的價值,表示我可以直接購買,可以替換的就連有向邊,邊權為替換的價錢,最後所求的就是從0到1的最短路。

比較一下兩種方案,事實上並沒有什麼區別。。。。。。但方案二提供了一個超級源的思路,可以借鑑。

程式碼:

#include<bits/stdc++.h>
using namespace std;
const int N=20010; const int M=250010;
struct Way{
	int to,next,val;
} way[M];
int c,n,m,k,a,cnt,cur,ans,minn,r,l,head[N],cost[N],grade[N],dis[N],num[N];
void add(int u,int v,int w){
	way[++cnt].next=head[u];
	way[cnt].to=v;
	way[cnt].val=w;
	head[u]=cnt;
}
queue<int>q;
void spfa(int st,int low){
	memset(num,0,sizeof(num));
	while(!q.empty()) q.pop();
	for(int i=1;i<=n;i++) dis[i]=M;
	if(grade[st]<low||grade[st]>low+c) return;
	q.push(st); dis[st]=cost[st];
	while(!q.empty()){
		cur=q.front(); q.pop(); num[cur]++;
		if(num[cur]>=n){
			ans=0; return;
		}
		for(int i=head[cur];i;i=way[i].next){
			if(grade[way[i].to]<low||grade[way[i].to]>low+c) continue;
			if(dis[way[i].to]>dis[cur]+cost[way[i].to]+way[i].val){
				dis[way[i].to]=dis[cur]+cost[way[i].to]+way[i].val;
				q.push(way[i].to);
			}
		}
	}
	for(int i=1;i<=n;i++)
		ans=min(ans,dis[i]);
}
int main(){
	freopen("data.in","r",stdin);
	scanf("%d %d",&c,&n);
	l=M; r=0;
	for(int i=1;i<=n;i++){
		scanf("%d %d %d",&cost[i],&grade[i],&m);
		l=min(l,grade[i]); r=max(r,grade[i]);
		for(int j=1;j<=m;j++){
			scanf("%d %d",&k,&a);
			add(i,k,a-cost[i]);
		}
	}
	ans=cost[1];
	for(int i=l;i+c<=r;i++)
		spfa(1,i);
	printf("%d",ans);
	return 0;
}