POJ1062
昂貴的聘禮
Description
年輕的探險家來到了一個印第安部落裏。在那裏他和酋長的女兒相愛了,於是便向酋長去求親。酋長要他用10000個金幣作爲聘禮才答應把女兒嫁給他。探險家拿不出這麼多金幣,便請求酋長降低要求。酋長說:"嗯,如果你能夠替我弄到大祭司的皮襖,我可以只要8000金幣。如果你能夠弄來他的水晶球,那麼只要5000金幣就行了。“探險家就跑到大祭司那裏,向他要求皮襖或水晶球,大祭司要他用金幣來換,或者替他弄來其他的東西,他可以降低價格。探險家於是又跑到其他地方,其他人也提出了類似的要求,或者直接用金幣換,或者找到其他東西就可以降低價格。不過探險家沒必要用多樣東西去換一樣東西,因爲不會得到更低的價格。探險家現在很需要你的幫忙,讓他用最少的金幣娶到自己的心上人。另外他要告訴你的是,在這個部落裏,等級觀念十分森嚴。地位差距超過一定限制的兩個人之間不會進行任何形式的直接接觸,包括交易。他是一個外來人,所以可以不受這些限制。但是如果他和某個地位較低的人進行了交易,地位較高的的人不會再和他交易,他們認爲這樣等於是間接接觸,反過來也一樣。因此你需要在考慮所有的情況以後給他提供一個最好的方案。
爲了方便起見,我們把所有的物品從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
題意
略
思路
如果此問題沒有等級交易限制,那麼就是一個標準的最短路徑——Dijkstra算法。
對於等級交易限制的處理,採用枚舉,即假設酋長等級爲5,等級限制爲2,那麼需要枚舉等級從35,46,5~7。從滿足改等級範圍的結點組成的子圖中用Dijkstra來算出最短路徑,最後求出最小值。
代碼
public class POJ1062 {
static int max = 9999999;
int n;
int m;
int[][] graph = new int[105][105];//圖
int[] value = new int[105];//物品的價值;
int[] level = new int[105];//物品擁有者的等級
boolean[] limit = new boolean[105];//標記,那些點參與某次計算
int[] dis = new int[105];//從開始點到各點到花費
boolean[] s = new boolean[105];//標記,點是否在s集合裏
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
POJ1062 p = new POJ1062();
int result = POJ1062.max;
p.m = sc.nextInt();//等級差距限制
p.n = sc.nextInt();//物品的總數
for (int i = 0; i <= p.n; i++) {
for (int j = 0; j <= p.n; j++) {
if (i == j) {
p.graph[i][j] = 0;
} else {
p.graph[i][j] = POJ1062.max;
}
}
}
for (int i = 1; i <= p.n; i++) {
p.value[i] = sc.nextInt();
p.level[i] = sc.nextInt();
int tmp = sc.nextInt();
for (int j = 1; j <= tmp; j++) {
int num = sc.nextInt();
int value = sc.nextInt();
p.graph[i][num] = value;
}
}
for (int i = 0; i <= p.m; i++) {
for (int j = 0; j < p.limit.length; j++) {
p.limit[j] = false;
}
for (int j = 1; j <= p.n; j++) {
if (p.level[j] <= p.level[1] + i && p.level[j] >= p.level[1] - p.m + i) {
p.limit[j] = true;
}
}
int tmp_result = p.dijkastra();
if (result > tmp_result) {
result = tmp_result;
}
}
System.out.println(result);
}
public int dijkastra() {
int result = max;
for (int i = 0; i < s.length; i++) {
s[i] = false;
}
for (int i = 1; i <= n; i++) {
if (i == 1) {
dis[i] = 0;
} else {
dis[i] = max;
}
}
for (int i = 1; i <= n; i++) {
int k = 0;
int tmp_dis = max;
for (int j = 1; j <= n; j++) {//找出未在s集合中且距離最短的點
if (!s[j] && dis[j] <= tmp_dis && limit[j]) {
tmp_dis = dis[j];
k = j;
}
}
s[k] = true;//添加到s集合中。
for (int j = 1; j <= n; j++) {
if (limit[j] && dis[j] > dis[k] + graph[k][j]) {//更新每個點到源點的距離
dis[j] = dis[k] + graph[k][j];
}
}
}
for (int i = 1; i <= n; i++) {
dis[i] = dis[i] + value[i];//每個路徑都需要添加上末尾節點的價值,否則是算了各邊的價錢合。
if (result > dis[i]) {
result = dis[i];
}
}
return result;
}
}