POJ 1062 昂贵的聘礼 (最短路)

时间:2023-03-08 16:41:39
POJ 1062 昂贵的聘礼 (最短路)

昂贵的聘礼

题目链接:

http://acm.hust.edu.cn/vjudge/contest/122685#problem/M

Description


年轻的探险家来到了一个印第安部落里。在那里他和酋长的女儿相爱了,于是便向酋长去求亲。酋长要他用10000个金币作为聘礼才答应把女儿嫁给他。探险家拿不出这么多金币,便请求酋长降低要求。酋长说:"嗯,如果你能够替我弄到大祭司的皮袄,我可以只要8000金币。如果你能够弄来他的水晶球,那么只要5000金币就行了。"探险家就跑到大祭司那里,向他要求皮袄或水晶球,大祭司要他用金币来换,或者替他弄来其他的东西,他可以降低价格。探险家于是又跑到其他地方,其他人也提出了类似的要求,或者直接用金币换,或者找到其他东西就可以降低价格。不过探险家没必要用多样东西去换一样东西,因为不会得到更低的价格。探险家现在很需要你的帮忙,让他用最少的金币娶到自己的心上人。另外他要告诉你的是,在这个部落里,等级观念十分森严。地位差距超过一定限制的两个人之间不会进行任何形式的直接接触,包括交易。他是一个外来人,所以可以不受这些限制。但是如果他和某个地位较低的人进行了交易,地位较高的的人不会再和他交易,他们认为这样等于是间接接触,反过来也一样。因此你需要在考虑所有的情况以后给他提供一个最好的方案。
为了方便起见,我们把所有的物品从1开始进行编号,酋长的允诺也看作一个物品,并且编号总是1。每个物品都有对应的价格P,主人的地位等级L,以及一系列的替代品Ti和该替代品所对应的"优惠"Vi。如果两人地位等级差距超过了M,就不能"间接交易"。你必须根据这些数据来计算出探险家最少需要多少金币才能娶到酋长的女儿。

Input


输入第一行是两个整数M,N(1

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

Hint




##题意:

通过一系列的以物换物使得用尽量小的本钱得到目标物品.
整个换物过程的阶级极差不能超过给定的值. (是整个过程,而不是一次交换的双方)


##题解:

把每个物品都看成图上的一个点. 对满足阶级要求的两个点连边(注意把起始点连接到其它所有点). 求最短路.

处理阶级差:
由于要求全过程的阶级最大差不超过某个值.
鉴于数据小,那么我们可以直接枚举这个差值,每次标记出符合这个差值的点来跑最短路,得出最小的结果.


##代码:
``` cpp
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LL long long
#define eps 1e-8
#define maxn 110
#define inf 0x3f3f3f3f
#define IN freopen("in.txt","r",stdin);
using namespace std;

int n,lim;

int value[maxn][maxn];

int dis[maxn];

bool vis[maxn];

int pre[maxn];

int cost[maxn];

int level[maxn];

int repnum[maxn];

int rep[maxn][maxn];

bool en[maxn];

void dijkstra(int s) {

memset(vis, 0, sizeof(vis));

for(int i=0; i<=n; i++) dis[i] = inf;

dis[s] = 0;

for(int i=0; i<=n; i++) {
int p, mindis = inf;
for(int j=0; j<=n; j++) {
if(en[j] && !vis[j] && dis[j]<mindis)
mindis = dis[p=j];
}
vis[p] = 1;
for(int j=0; j<=n; j++) {
if(en[j] && dis[j] > dis[p]+value[p][j]) {
dis[j] = dis[p] + value[p][j];
pre[j] = p;
}
}
}

}

int main(int argc, char const *argv[])

{

//IN;

while(scanf("%d %d", &lim,&n) != EOF)
{
for(int i=0; i<maxn; i++)
for(int j=0; j<maxn; j++)
value[i][j] = inf;
memset(rep, -1, sizeof(rep)); int minlev = inf, maxlev = -inf;
for(int i=1; i<=n; i++){
scanf("%d %d %d", &cost[i],&level[i],&repnum[i]);
minlev = min(minlev, level[i]);
maxlev = max(maxlev, level[i]);
/*直接用本钱购买*/
value[0][i] = cost[i];
for(int j=1; j<=repnum[i]; j++) {
int a,b; scanf("%d %d", &a,&b);
rep[i][a] = b;
}
} for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
if(abs(level[i]-level[j]) > lim) continue;
if(rep[j][i] == -1) continue;
value[i][j] = rep[j][i];
}
} int ans = inf;
/*枚举级别差*/
for(int i=minlev; i<=maxlev; i++) {
int mi = i;
int ma = i + lim;
memset(en, 0, sizeof(en)); en[0]=1;
for(int i=1; i<=n; i++) {
if(level[i]>=mi && level[i]<=ma)
en[i] = 1;
}
dijkstra(0);
ans = min(ans, dis[1]);
if(i+lim>maxlev) break;
} printf("%d\n", ans);

// int p = 1;

// while(1) {

// printf("%d ", p);

// if(p == 0) break;

// p = pre[p];

// }

}

return 0;

}