<題目鏈接>? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? 昂貴的聘禮
Description
年輕的探險家來到了一個印第安部落里。在那里他和酋長的女兒相愛了,于是便向酋長去求親。酋長要他用10000個金幣作為聘禮才答應把女兒嫁給他。探險家拿不出這么多金幣,便請求酋長降低要求。酋長說:"嗯,如果你能夠替我弄到大祭司的皮襖,我可以只要8000金幣。如果你能夠弄來他的水晶球,那么只要5000金幣就行了。"探險家就跑到大祭司那里,向他要求皮襖或水晶球,大祭司要他用金幣來換,或者替他弄來其他的東西,他可以降低價格。探險家于是又跑到其他地方,其他人也提出了類似的要求,或者直接用金幣換,或者找到其他東西就可以降低價格。不過探險家沒必要用多樣東西去換一樣東西,因為不會得到更低的價格。探險家現在很需要你的幫忙,讓他用最少的金幣娶到自己的心上人。另外他要告訴你的是,在這個部落里,等級觀念十分森嚴。地位差距超過一定限制的兩個人之間不會進行任何形式的直接接觸,包括交易。他是一個外來人,所以可以不受這些限制。但是如果他和某個地位較低的人進行了交易,地位較高的的人不會再和他交易,他們認為這樣等于是間接接觸,反過來也一樣。因此你需要在考慮所有的情況以后給他提供一個最好的方案。?
為了方便起見,我們把所有的物品從1開始進行編號,酋長的允諾也看作一個物品,并且編號總是1。每個物品都有對應的價格P,主人的地位等級L,以及一系列的替代品Ti和該替代品所對應的"優惠"Vi。如果兩人地位等級差距超過了M,就不能"間接交易"。你必須根據這些數據來計算出探險家最少需要多少金幣才能娶到酋長的女兒。?
為了方便起見,我們把所有的物品從1開始進行編號,酋長的允諾也看作一個物品,并且編號總是1。每個物品都有對應的價格P,主人的地位等級L,以及一系列的替代品Ti和該替代品所對應的"優惠"Vi。如果兩人地位等級差距超過了M,就不能"間接交易"。你必須根據這些數據來計算出探險家最少需要多少金幣才能娶到酋長的女兒。?
Input
輸入第一行是兩個整數M,N(1 <= N <= 100),依次表示地位等級差距限制和物品的總數。接下來按照編號從小到大依次給出了N個物品的描述。每個物品的描述開頭是三個非負整數P、L、X(X < N),依次表示該物品的價格、主人的地位等級和替代品總數。接下來X行每行包括兩個整數T和V,分別表示替代品的編號和"優惠價格"。
Output
輸出最少需要的金幣數。
Sample Input
1 4
10000 3 2
2 8000
3 5000
1000 2 1
4 200
3000 2 1
4 200
50 2 0
Sample Output
5250
解題分析:
首先,本題要解決如何讓交換的所有人等級之差不超過k,因為在松弛操作的時候有很多種情況,所以我們不能通過簡單的判斷去簡化這個問題,只能暴力枚舉符合條件的等級區間,因為枚舉的區間一定要包含酋長,所以枚舉區間為[node[1].lev-k,node[1].lev]……[node[1].lev,node[1].lev+k]。枚舉區間確定后,就要解決dijkstra的松弛問題了。
本題圖解分析如下:
以上這種貪心松弛策略是錯的(T_T),因為我們可以通過交易其他的物品來減少當前物品的花費,所以如果你直接加上當前點的基礎價格就不能保證每次找的都是當前最短的的那條路的終點。正解是先求出起點到達每個點的最短路,然后再加上終點物品的基礎價值,最后進行比較。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 #define INF 0x3f3f3f3f 7 int k,n,le,ri; 8 int dis[110],mpa[110][110]; 9 struct NODE{ 10 int val,lev; 11 }node[110]; 12 bool vis[110]; 13 void dij(){ 14 memset(vis,false,sizeof(vis)); 15 memset(dis,INF,sizeof(dis)); 16 //dis[1]=node[1].val; 17 dis[1]=0; 18 int cur=1; 19 for(int i=1;i<=n;i++){ 20 vis[cur]=true; 21 for(int j=1;j<=n;j++){ 22 /*if(!vis[j]&&node[j].lev>=le&&node[j].lev<=ri&&dis[j]>dis[cur]-node[cur].val+mpa[cur][j]+node[j].val){ 23 dis[j]=dis[cur]-node[cur].val+mpa[cur][j]+node[j].val; 24 }*/ //這種方法會WA 25 if(!vis[j]&&node[j].lev>=le&&node[j].lev<=ri&&dis[j]>dis[cur]+mpa[cur][j]){ 26 dis[j]=dis[cur]+mpa[cur][j]; 27 } 28 } 29 int res=INF; 30 for(int j=1;j<=n;j++){ 31 if(!vis[j]&&node[j].lev>=le&&node[j].lev<=ri&&dis[j]<res){ 32 res=dis[j]; 33 cur=j; 34 } 35 } 36 } 37 } 38 int main(){ 39 while(scanf("%d%d",&k,&n)!=EOF){ 40 memset(mpa,INF,sizeof(mpa)); 41 for(int i=1;i<=n;i++){ 42 int m;scanf("%d%d%d",&node[i].val,&node[i].lev,&m); 43 while(m--){ 44 int v,w; 45 scanf("%d%d",&v,&w); 46 if(w<mpa[i][v])mpa[i][v]=w; //建立這個物品到其它可交換物品的邊 47 } 48 } 49 int ans=INF; 50 le=node[1].lev-k,ri=node[1].lev; 51 while(le<=node[1].lev){ 52 dij(); 53 for(int i=1;i<=n;i++){ 54 //ans=min(ans,dis[i]); 55 ans=min(ans,dis[i]+node[i].val); //算出到所有物品的最短路徑,最后再加上終點物品的價值 56 } 57 le++,ri++; 58 } 59 printf("%d\n",ans); 60 } 61 return 0; 62 }
2018-08-31