Big Truck
Photo by Phil Whitehouse
Your boss has hired you to drive a big truck, transporting items between two locations in a city. You’re given a description of the city, with locations of interest and the lengths of roads between them. Your boss requires that you take a shortest path between the starting and ending location, and she’ll check your odometer when you’re done to make sure you didn’t take any unnecessary side trips. However, your friends know you have plenty of unused space in the truck, and they have asked you to stop by several locations in town, to pick up items for them. You’re happy to do this for them. You may not be able to visit every location to pick up everything your friends want, but you’d like to pick up as many items as possible on your trip, as long as it doesn’t make the path any longer than necessary.
Figure 1: Illustrations of the first two sample inputs
The two graphs above show examples of what the city may look like, with nodes representing locations, edges representing roads and dots inside the nodes representing items your friends have asked you to pick up. Driving through a location allows you to pick up all the items there; it’s a big truck, with no limit on the items it can carry. In the graph on the left, for example, you have to drive the big truck from location 1<?XML:NAMESPACE PREFIX = "[default] http://www.w3.org/1998/Math/MathML" NS = "http://www.w3.org/1998/Math/MathML" />1 to location 66. If you follow the path 1→2→3→61→2→3→6, the length is 99, and you’ll get to pick up 44 items. Of course, it would be better to drive 1→4→5→61→4→5→6; that’s still a length of 99, but going this way instead lets you pick up an additional item. Driving 1→4→3→61→4→3→6 would let you pick up even more items, but it would make your trip longer, so you can’t go this way.
Input
The first line of input contains an integer, nn (2≤n≤1002≤n≤100), giving the number of locations in the city. Locations are numbered from 11 to nn, with location 11 being the starting location and nn being the destination. The next input line gives a sequence of nn integers, t1…tnt1…tn, where each titi indicates the number of items your friends have asked you to pick up from location ii. All the titi values are between 00 and 100100, inclusive. The next input line contains a non-negative integer, mm, giving the number of roads in the city. Each of the following mm lines is a description of a road, given as three integers, abdabd. This indicates that there is a road of length dd between location aa and location bb. The values of aa and bb are in the range 1…n1…n, and the value of dd is between 11 and 100100, inclusive. All roads can be traversed in either direction, there is at most one road between any two locations, and no road starts and ends at the same location.
Output
If it’s not possible to travel from location 11 to location nn, just output out the word “impossible”. Otherwise, output the length of a shortest path from location 11 to location nn, followed by the maximum number of items you can pick up along the way.
Sample Input 1
Sample Output 1
6 1 1 2 3 1 0 7 1 2 2 2 3 3 3 6 4 1 4 4 4 3 2 4 5 3 5 6 2
9 5
Sample Input 2
Sample Output 2
9 1 1 1 1 1 1 1 1 1 10 1 2 3 2 5 3 1 6 2 6 7 2 7 5 2 5 3 1 3 4 2 4 9 3 5 8 2 8 9 4
12 7
Sample Input 3
Sample Output 3
2 5 5 0
impossible
这道题一看之下是一道dijkstra寻找最短路的问题,但是真的是一道dijkstra寻找最短路的问题(事实上在官方给出的题解中还有另一种我看不懂的解法)
然后在D算法寻找最短路的过程中,在一个已经被找到最短路的点对所有相连点的更新中,若其发现了更短的路,则当前点更新为最短路能携带的最大物品数量,若其路径和当前的最短路相同,则将点里的物品数更新为较大的那个,一开始就大概想出了这个思路,但是由于一个用优先队列优化dijkstra算法的基础错误(优先队列内部实现采用堆结构,但是D算法在对于一个节点的处理中可能对于内部的多个节点的数据进行更新,这种更新并不伴随着堆结构的维护,所以使得排序出错)从下午想出思路找bug找到凌晨,啊……用优先队列维护D算法有风险。
以下是代码:
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<vector>
#include<algorithm>
#include<string>
#include<queue>
#include<climits>
#define MAX 3000
#define math 1000
using namespace std;
struct vert {
int id;
int ite;
int ite_n = 0;
int dis = INT_MAX;
vector<vert*>child;
vector<int>test;
};
int comp(vert* a, vert* b) {
return a->dis < b->dis;
};
vector<vert>sto;
vector<vert*>Q;
int dis[MAX][MAX] = { 0 };
int vst[MAX] = { 0 };
int main(void)
{
int n, m;
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
vert temp;
temp.id = i;
scanf("%d", &temp.ite);
sto.push_back(temp);
}
scanf("%d", &m);
for (int i = 0; i < m; i++)
{
int a, b, d;
scanf("%d %d %d", &a, &b, &d);
a--, b--;
sto[a].child.push_back(&sto[b]);
sto[b].child.push_back(&sto[a]);
dis[a][b] = d;
dis[b][a] = d;
}
//input
sto[0].dis = 0;
Q.push_back(&sto[0]);
vst[0] = 1;
sto[0].ite_n = sto[0].ite;
while (!Q.empty())
{
vert temp = *Q.front();
Q.erase(Q.begin());
int siz = temp.child.size();
int ind_t = temp.id;
for (int i = 0; i < temp.child.size(); i++)
{
int ind_c = temp.child[i]->id;
if (temp.dis + dis[ind_t][ind_c] < sto[ind_c].dis)//update
{
sto[ind_c].dis = temp.dis + dis[ind_t][ind_c];
sto[ind_c].ite_n = sto[ind_t].ite_n + sto[ind_c].ite;
}
else if (temp.dis + dis[ind_t][ind_c] == sto[ind_c].dis)
{
sto[ind_c].ite_n = max(sto[ind_t].ite_n + sto[ind_c].ite, sto[ind_c].ite_n);
}
if (!vst[ind_c])//check if already visited
{
Q.push_back(&sto[ind_c]);
vst[ind_c] = 1;
}
}
sort(Q.begin(), Q.end(), comp);
}
if (sto[n - 1].dis != INT_MAX)
cout << sto[n - 1].dis << " " << sto[n - 1].ite_n;
else
cout << "impossible";
}
附赠趣图: