題目大意是說有N個物品,每個物品都有自己的價格,但同時某些物品也可以由其他的(可能不止一個)替代品,這些替代品的價格比較“優惠”,問怎么樣選取可以讓你的花費最少來購買到物品1
由於有N個物品,我們就可以把它們看作是N個點,從其他點到他的優惠關系視做邊,又因為最后總是要找到物品1,所以可以看作是從起點0,到將物品1作為終點的最小路勁。然后由於題目是說,這條路勁上不能有兩個的等級差超過M,所以我們可以枚舉最小等級,將每個點視作最小等級,這樣的話就不會掉解。
又由於我們是枚舉的最小等級,所以源點0到其他每個點的邊的權值就要賦值為那個點的價格,降等級比最小等級要大,或者差距大於M的其他點標記為不合法(也就是不可以走),然后在從合法的路勁中找出最小花費。
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 #include<map> 5 #include<vector> 6 #include<set> 7 #include<stack> 8 #include<queue> 9 #include<algorithm> 10 #include<stdlib.h> 11 using namespace std; 12 #define MAX(a,b) (a > b ? a : b) 13 #define MIN(a,b) (a < b ? a : b) 14 #define mem(a) memset(a,0,sizeof(a)) 15 #define MAXN 105 16 #define INF 1000000007 17 18 int Price[MAXN],Edge[MAXN][MAXN],Level[MAXN]; 19 int vis[MAXN], d[MAXN]; 20 int N,M,ans; 21 22 void init() 23 { 24 mem(Price); mem(Level); 25 for(int i=0;i<=N;i++) 26 { 27 for(int j=0;j<=N;j++) 28 { 29 Edge[i][j] = INF;//初始化每條邊都是不連通的 30 } 31 } 32 } 33 34 void read() 35 { 36 int i,j,X,T,TP; 37 for(i=1;i<=N;i++) 38 { 39 scanf("%d%d%d",&Price[i], &Level[i], &X); 40 for(j=0;j<X;j++) 41 { 42 scanf("%d %d", &T, &TP); 43 Edge[T][i] = TP;//記錄邊 44 } 45 Edge[0][i] = Price[i]; 46 } 47 } 48 49 int dijkstra() 50 { 51 for(int i=1;i<=N;i++)d[i] = Price[i];//源點0到每個點的權值賦為這個點的價格 52 for(int i=1;i<=N;i++) 53 { 54 int temp = INF,x; 55 for(int j=1;j<=N;j++)if(!vis[j] && d[j]<=temp)temp = d[x = j]; 56 vis[x] = 1; 57 for(int j=1;j<=N;j++)if(d[x]+Edge[x][j] < d[j] && !vis[j])d[j] = d[x]+Edge[x][j];//要從合法的物品中選取,加上!vis[j] 58 } 59 return d[1];//這里找到的最小值是未知起點的最小值 60 } 61 62 int main() 63 { 64 while(~scanf("%d %d", &M, &N)) 65 { 66 init(); 67 read(); 68 ans = INF; 69 for(int i=1;i<=N;i++) 70 { 71 int minLevel = Level[i];//將目前的點視作等級最高的點 72 for(int j=1;j<=N;j++) 73 { 74 if(Level[j] - minLevel > M || minLevel > Level[j])vis[j] = 1;//如果有比它還低的點,或者差超過M,視為不合法 75 else vis[j] = 0; 76 } 77 int now = dijkstra(); 78 ans = MIN(ans, now); 79 } 80 printf("%d\n", ans); 81 } 82 return 0; 83 }