轉載請注明出處:優 YoU http://user.qzone.qq.com/289065406/blog/1299338542
?
提示:難得的中文題。。雖然語言相通但是不好解決。。。都說便宜沒好貨,這是真的= =
最短路問題,dijkstra算法的運用。。。很多同學對dijkstra有一種與生俱來的恐懼,首當其沖就是它的名字。。說實在我現在也不知道怎么念它O(∩_∩)O哈哈~其實dijkstra很簡單的,最難也就它的名字,不懂得同學去翻書,這里我不解釋dijkstra,我只說一個我認為能夠很好理解dijkstra精髓的關鍵點:
? 新源點合并到舊源點時,新源點到舊源點的邊權的移交(也可理解為松弛)
?
弄清了這個,dijkstra就不難了,我覺得dijkstra和Prim有異曲同工之妙
?
每個物品看成一個節點,
酋長的允諾也看作一個物品,
如果一個物品加上金幣可以交換另一個物品,
則這兩個節點之間有邊,權值為金幣數,求第一個節點到所有節點的最短路。
因為有等級限制,所以枚舉每個點作為最低等級,選取符合所有符合等級
限制
的點
最短路問題,不過因為存在著等級的差異所以需要枚舉一下。本題的思路就是對冒險者的等級進行枚舉,也就是說冒險者只能和在他等級以上的人進行交易。這樣枚舉的好處是能夠把所有的情況都考慮進去。有一點需要注意:酋長的等級不一定是最高的
構圖時要注意的是,酉長的承諾不是
最初的源點,它是一個目標點,也就是說點到點的指向方向是由
無替代品的點
逐漸指向到
酉長的承諾
1
點,題意說明的是一個回溯的過程,因此可以定義一個最初的源點
0
點,它到其他各點的權值就是每個物品的原價,而點
A
到點
B
的權值
就是
物品
B
在有第
A
號替代品情況下的優惠價
?
1
//
Memory Time
2
//
300K 32MS
3
4
#include
<
iostream
>
5
using
namespace
std;
6
7
const
int
inf
=
0x7fffffff
;
//
無限大
8
9
int
M,N;
//
M為等級差,N為物品數目
10
int
price[
101
][
101
];
//
物品i在有第t號替代品情況下的優惠價pricr[t][i],當t=0時說明i無替代品,此時為原價
11
int
lv[
101
];
//
第i號物品主人的等級lv[i]
12
int
x[
101
];
//
第i號物品的替代品總數x[i]
13
14
int
dist[
101
];
//
最初的源點0到任意點i的最初距離(權值),相當于每個物品的原價
15
16
bool
vist[
101
];
//
記錄點i是否已被訪問
17
18
/*
Initial and Input
*/
19
20
void
data_init()
21
{
22
memset(price,
0
,
sizeof
(price));
23
memset(lv,
0
,
sizeof
(lv));
24
memset(dist,inf,
sizeof
(dist));
25
memset(vist,
false
,
sizeof
(vist));
26
27
cin
>>
M
>>
N;
28
for
(
int
i
=
1
;i
<=
N;i
++
)
29
{
30
cin
>>
price[
0
][i]
>>
lv[i]
>>
x[i];
//
price[0][i]物品i無替代品時的原價
31
32
for
(
int
j
=
1
;j
<=
x[i];j
++
)
33
{
34
int
t,u;
//
t替代品編號,u優惠價(臨時變量)
35
cin
>>
t
>>
u;
36
price[t][i]
=
u;
//
物品i在有第t號替代品情況下的優惠價,即點t到點i的權值
37
}
38
}
39
}
40
41
/*
Dijkstra Algorithm
*/
42
43
int
dijkstra()
44
{
45
46
int
node;
//
記錄與當前源點距離最短的點
47
int
sd;
//
最短距離
48
int
i,j;
49
50
for
(i
=
1
;i
<=
N;i
++
)
51
dist[i]
=
price[
0
][i];
//
假設最初的源點就是0點,初始化最初源點到各點的權值dist[i]
52
53
for
(i
=
1
;i
<=
N;i
++
)
//
由于1點是目標點,因此最壞的打算是進行n次尋找源點到其他點的最短路,并合并這兩點(不再訪問相當于合并了)
54
{
55
node
=
0
;
56
sd
=
inf;
57
for
(j
=
1
;j
<=
N;j
++
)
58
{
59
if
(
!
vist[j]
&&
sd
>
dist[j])
//
在未訪問的點中,尋找最短的一條
60
{
61
sd
=
dist[j];
62
node
=
j;
//
記錄該點
63
}
64
}
65
if
(node
==
0
)
//
若node沒有變化,說明所有點都被訪問,最短路尋找完畢
66
break
;
67
68
vist[node]
=
true
;
//
記錄node點已被訪問
69
for
(j
=
1
;j
<=
N;j
++
)
70
{
71
if
(
!
vist[j]
&&
price[node][j]
>
0
&&
dist[j]
>
dist[node]
+
price[node][j])
//
把未訪問但與node(新源點)連通的點進行松弛
72
dist[j]
=
dist[node]
+
price[node][j];
73
}
74
}
75
return
dist[
1
];
//
返回當前次交易后目標點1在等級lv[i]約束下的最短距離
76
}
77
78
int
main()
79
{
80
data_init();
//
初始化并輸入數據
81
82
int
temp_price;
//
當前次交易后目標點1在等級lv[i]約束下的最少價格
83
int
maxlv;
//
最大等級(酉長的等級不一定是最大的)
84
int
minprice
=
inf;
//
最低價格(初始化為無限大)
85
86
for
(
int
i
=
1
;i
<=
N;i
++
)
87
{
88
/*
在等級限制下,尋找允許被當前點訪問的點
*/
89
90
maxlv
=
lv[i];
//
把當前物品的等級暫時看做最高等級
91
for
(
int
j
=
1
;j
<=
N;j
++
)
//
遍歷其他各點
92
{
93
if
(lv[j]
>
maxlv
||
maxlv
-
lv[j]
>
M)
//
當其它物品j的等級比當前物品高(保證單向性),或者兩者等級之差超出限制M時
94
vist[j]
=
true
;
//
物品j則強制定義為“已訪問”狀態,不參與后續操作
95
else
96
vist[j]
=
false
;
//
否則物品j定義為“未訪問”狀態,參與后續操作
97
}
98
99
temp_price
=
dijkstra();
//
記錄當前次交易后目標點1在等級lv[i]約束下的最短距離(最少價格)
100
101
if
(minprice
>
temp_price)
//
尋找各次交易后的最少價格,最終確認最少價格
102
minprice
=
temp_price;
103
}
104
cout
<<
minprice
<<
endl;
105
106
return
0
;
107
}
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

