大致题意:
有N个物品,N个物品都有对应的价格,但是在已有某些物品的情况下可以对某些物品减价,求获取第一个物品最低需要花费的金币数。另外每个物品都有对应的等级,在减价的过程中等级差不能超过给定值。
解题思路:
将物品作为结点,减价关系作为边,构成一幅图。可以用Dijkstra算法求得单源最短路径,求出最少需要花费的金币数。注意等级差的问题。设最大允许等级差为order,第一个物品的等级为rank1,可知最短路径上的结点等级需要在[rank1-order, rank1+order]区间内,这样虽然最短路径上其它结点和第一个结点满足等级差条件,但是其它结点之间不一定满足等级差条件。一种解决办法是枚举[rank1-order, rank1]、[rank1-order+1, rank1+1]、……、[rank1, rank1+order]共order+1个区间(等级在这些区间内的结点都满足等级差条件),分别计算满足这些区间的最短路径,从而得到满足等级差条件的最短路径。
C++代码:
//Memory Time
//312K 79MS
#include <iostream>
using namespace std;
struct node{
int num;//结点编号
int weight;//边权值
node *next;
};
node goods[101];//物品结点
bool fitrank[101];//结点是否满足等级条件
int dis[101];//距离
class prior_queue{
private:
int a[105];
int front;
int rear;
public:
prior_queue():front(0), rear(0) {}
void enqueue(int num){
a[rear] = num;
rear = (rear+1)%105;
}
int extract_min(){
int min_loc = front;
for(int i = front; i != rear; i = (i+1)%105){
if(dis[a[i]] < dis[a[min_loc]]){
min_loc = i;
}
}
int result = a[min_loc];
a[min_loc] = a[front];
front = (front+1)%105;
return result; //返回具有最小距离的结点编号
}
bool is_empty(){
if(front == rear)
return true;
else
return false;
}
};
//dijkstra算法,求单源最短路径
void dijkstra(node ns[], int n){
//初始化距离
for(int i = 1; i <= n; i++)
dis[i] = 0x7fffffff;
dis[1] = 0;
prior_queue q;
for(int i = 1; i <= n; i++)
q.enqueue(ns[i].num);
while(!q.is_empty()){
int num = q.extract_min();
if(fitrank[num] == false || dis[num] == 0x7fffffff)
continue;
node* n = &ns[num];
while(n->next != NULL){
node* n2 = n->next;
if(fitrank[n2->num] == false){ //该结点不符合等级差条件
n = n2;
continue;
}
if(dis[n2->num] > dis[num] + n2->weight){
dis[n2->num] = dis[num] + n2->weight;
}
n = n2;
}
}
}
int main()
{
int order, goods_num;
cin >> order >> goods_num;
int value[101]; //每个物品的价格
int rank[101]; //每个物品的地位
//初始化goods[]
for(int i = 1; i <= goods_num; i++){
goods[i].next = NULL;
goods[i].num = i;
goods[i].weight = 0;
}
for(int i = 1; i <= goods_num; i++){
int edge_num;
cin >> value[i] >> rank[i] >> edge_num;
for(int j = 0; j < edge_num; j++){
node* n1 = new node;
cin >> n1->num >> n1->weight;
n1->next = NULL;
node *p = &goods[i];
while(p->next != NULL){
p = p->next;
}
p->next = n1;
}
}
//计算最少的金币数
int min_distance = 0x7fffffff;
for(int x = 0; x <= order; x++){
for(int i = 1; i <= goods_num; i++){
fitrank[i] = true;
}
//标记不符合等级差条件的结点
for(int i = 2; i <= goods_num; i++){
if(rank[i] - rank[1] < x - order || rank[i] - rank[1] > x)
fitrank[i] = false;
}
//计算单源最短路径
dijkstra(goods, goods_num);
for(int i = 1; i <= goods_num; i++){
if(dis[i] == 0x7fffffff){
continue;
}
if(min_distance > dis[i] + value[i]){
min_distance = dis[i] + value[i];
}
}
}
cout << min_distance << endl;
//释放动态分配的内存
for(int i = 1; i <= goods_num; i++){
node *p = goods[i].next;
while(p != NULL){
node *p2 = p;
p = p->next;
delete p2;
}
}
return 0;
}