POJ_1062 昂贵的聘礼 Dijkstra
来源:互联网 发布:ubuntu 用户提权 编辑:程序博客网 时间:2024/06/12 13:13
题目连接 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 0x3f3f3f3fstruct 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 410000 3 22 80003 50001000 2 14 2003000 2 14 20050 2 05250测试数据2:1 510000 3 42 30003 20004 20005 90008000 2 33 50004 20005 70005000 1 02000 4 15 190050 1 04000测试数据3:3 810000 3 62 30003 20004 20005 90007 10008 50088000 2 33 50004 20005 70005000 1 16 10002000 4 15 190050 1 05000 1 17 40072000 4 15 190080 3 02950测试数据4:1 101324 0 01234 0 0255 0 067 0 056 0 02134 0 0456 0 02345 0 067 0 06436 0 01324测试数据5: ///debug 一整条交易向上的等级差异都不能超过 m///这里帮助我纠正了第一次写的算法,当时以为等级差只是在某一条边的两端不能超过m1 410000 3 22 13 31000 2 24 13 11000 3 14 2100 4 0105测试数据6:3 510000 3 42 30003 20004 20005 90008000 2 33 50004 20005 70005000 1 02000 4 15 190050 1 03950测试数据7:0 510000 3 42 30003 20004 20005 90008000 2 33 50004 20005 70005000 4 02000 3 15 190050 2 04000*/
阅读全文