题目连接 https://vjudge.net/problem/POJ-1062
本题为 Dijkstra 的应用
储存结构:
所有的替代品关系都可以储存在边上,酋长的承诺,应作为最终的终点“1”
另外应虚设一个结点“0”,“0”到“1->n”的n条有向边储存商品的原价
实现原理:
每一趟 Dijkstra 以枚举出来的最小等级跑一边,把“0”作为源点,最后取酋长承诺点“1”的各个 mincost[1] 值的最小值
最小等级枚举的说明:
图上一条路径可以看作整条交易链,宅整条交易的过程中高低等级悬殊不可以超过m,可以通过“枚举最小等级”的方法来实现
依次将“1->n”n个结点的等级作为最小等级,跑一边Dijkstra,沿着边向外拓展维护的时候,弧头结点等级与最小等级差超过 m,或者弧头节点等级小于最小等级,都是为边不可达
AC关键代码:
#define PP pair<int, int>
#define INF 0x3f3f3f3f
struct edge{
int u, v;
int to, cost;
bool operator < (const edge &right) const {
return cost < right.cost;
}
};
const int maxn = 100 + 10;
int m, n;
vector<edge> G[maxn];
int mincost[maxn];
int value[maxn];
int level[maxn];
void init()
{
cin >> m >> n;
edge buf;
int u, x;
for (int i = 1; i <= n; i ++){
scanf("%d%d%d", &value[i], &level[i], &x);
buf.to = i;
for (int j = 0; j < x; j ++){
scanf("%d%d", &u, &buf.cost);
G[u].push_back(buf);
}
}
for (int i = 1; i <= n; i ++){
buf.to = i;
buf.cost = value[i];
G[0].push_back(buf);
}
}
void manage(int minlevel)
{
priority_queue<PP, vector<PP>, greater<PP> > qq;
qq.push(PP(0, 0));
mem(mincost, INF);
mincost[0] = 0;
PP p;
while (!qq.empty()){
p = qq.top();
qq.pop();
int u = p.second;
if (p.first > mincost[u]) continue;
//refresh mincost
for (int i = 0; i < G[u].size(); i ++){
edge e = G[u][i];
if (!(level[e.to]-minlevel>m || level[e.to]<minlevel)){ //accessibility
if (mincost[e.to] > mincost[u]+e.cost){
mincost[e.to] = mincost[u]+e.cost;
qq.push(PP(mincost[e.to], e.to));
}
}
}
}
}
void solve()
{
int ans = INF;
for (int j = 1; j <= n; j ++){
manage(level[j]);
ans = min(ans, mincost[1]);
}
cout << ans << endl;
}
附WA关键代码:
const int maxn = 100 + 10;
int m, n;
vector<edge> G[maxn];
int mincost[maxn];
int value[maxn];
int level[maxn];
void init()
{
cin >> m >> n;
edge buf;
int x;
for (int i = 1; i <= n; i ++){
scanf("%d%d%d", &value[i], &level[i], &x);
for (int j = 0; j < x; j ++){
scanf("%d%d", &buf.to, &buf.cost);
G[i].push_back(buf);
}
}
}
void manage(int minlevel)
{
priority_queue<PP, vector<PP>, greater<PP> > qq;
qq.push(PP(0, 1));
mem(mincost, INF);
mincost[1] = 0;
PP p;
while (!qq.empty()){
p = qq.top();
qq.pop();
int u = p.second;
if (p.first > mincost[u]) continue;
//refresh mincost
for (int i = 0; i < G[u].size(); i ++){
edge e = G[u][i];
if (!(level[e.to]-minlevel>m || level[e.to]<minlevel)){
if (mincost[e.to] > mincost[u]+e.cost){
mincost[e.to] = mincost[u]+e.cost;
qq.push(PP(mincost[e.to], e.to));
}
}
}
}
}
void solve()
{
int ans = INF;
for (int j = 1; j <= n; j ++){
manage(level[j]);
for (int i = 1; i <= n; i ++){
mincost[i] += value[i];
ans = min(ans, mincost[i]);
}
}
cout << ans << endl;
}
这里借鉴一下其他大佬的测试样例(上面的WA版代码能通过全部测试样例):
/*
测试数据1:
1 4
10000 3 2
2 8000
3 5000
1000 2 1
4 200
3000 2 1
4 200
50 2 0
5250
测试数据2:
1 5
10000 3 4
2 3000
3 2000
4 2000
5 9000
8000 2 3
3 5000
4 2000
5 7000
5000 1 0
2000 4 1
5 1900
50 1 0
4000
测试数据3:
3 8
10000 3 6
2 3000
3 2000
4 2000
5 9000
7 1000
8 5008
8000 2 3
3 5000
4 2000
5 7000
5000 1 1
6 1000
2000 4 1
5 1900
50 1 0
5000 1 1
7 4007
2000 4 1
5 1900
80 3 0
2950
测试数据4:
1 10
1324 0 0
1234 0 0
255 0 0
67 0 0
56 0 0
2134 0 0
456 0 0
2345 0 0
67 0 0
6436 0 0
1324
测试数据5:
///debug 一整条交易向上的等级差异都不能超过 m
///这里帮助我纠正了第一次写的算法,当时以为等级差只是在某一条边的两端不能超过m
1 4
10000 3 2
2 1
3 3
1000 2 2
4 1
3 1
1000 3 1
4 2
100 4 0
105
测试数据6:
3 5
10000 3 4
2 3000
3 2000
4 2000
5 9000
8000 2 3
3 5000
4 2000
5 7000
5000 1 0
2000 4 1
5 1900
50 1 0
3950
测试数据7:
0 5
10000 3 4
2 3000
3 2000
4 2000
5 9000
8000 2 3
3 5000
4 2000
5 7000
5000 4 0
2000 3 1
5 1900
50 2 0
4000
*/