大白书 P341这题说的是给了NT种飞机票,给了价钱和整个途径,给了nI条要旅游的路线。使用飞机票都必须从头第一站开始坐,可以再这个路径上的任何一点下飞机一但下飞机了就不能再上飞机,只能重新买票,对于每张票使用的状态有经过了这个路途的前i个点使用它,那么点就有,n*len(n为城市编号,为旅途所经过的所有点的个数),每张票在已经走完第一个点使用,第二个点,第三个点使用。。。最后从经过第一个点的旅途开始地方跑最长路,直到跑了len 旅途结束的点。
// LA3561 Low Cost Air Travel #include<cstdio> #include<cstring> #include<queue> #include<algorithm> using namespace std; const int INF = 1000000000; const int maxn = 4000 + 10; struct Edge { int from, to, dist, val; }; struct HeapNode { int d, u; bool operator < (const HeapNode& rhs) const { return d > rhs.d; } }; struct Dijkstra { int n, m; vector<Edge> edges; vector<int> G[maxn]; bool done[maxn]; // 是否已永久标号 int d[maxn]; // s到各个点的距离 int p[maxn]; // 最短路中的上一条弧 void init(int n) { this->n = n; for(int i = 0; i < n; i++) G[i].clear(); edges.clear(); } void AddEdge(int from, int to, int dist, int val) { edges.push_back((Edge){from, to, dist, val}); m = edges.size(); G[from].push_back(m-1); } void dijkstra(int s) { priority_queue<HeapNode> Q; for(int i = 0; i < n; i++) d[i] = INF; d[s] = 0; memset(done, 0, sizeof(done)); Q.push((HeapNode){0, s}); while(!Q.empty()) { HeapNode x = Q.top(); Q.pop(); int u = x.u; if(done[u]) continue; done[u] = true; for(int i = 0; i < G[u].size(); i++) { Edge& e = edges[G[u][i]]; if(d[e.to] > d[u] + e.dist) { d[e.to] = d[u] + e.dist; p[e.to] = G[u][i]; Q.push((HeapNode){d[e.to], e.to}); } } } } vector<int> GetShortestPath(int s, int t) { vector<int> path; while(t != s) { path.push_back(edges[p[t]].val); t = edges[p[t]].from; } reverse(path.begin(), path.end()); return path; } }; //////// 题目相关 #include<map> int n_cities; map<int,int> city_id; int ID(int city) { if(city_id.count(city)) return city_id[city]; city_id[city] = n_cities++; return n_cities-1; } int ID(int visited, int cur) { return (visited-1) * n_cities + cur; } const int maxnt = 100; int cost[maxnt]; vector<int> cities[maxnt], iti; Dijkstra solver; int main() { int NT, NI, x, len, kase = 0; while(scanf("%d", &NT) == 1 && NT) { n_cities = 0; city_id.clear(); for(int i = 0; i < NT; i++) { cities[i].clear(); scanf("%d%d", &cost[i], &len); while(len--) { scanf("%d", &x); cities[i].push_back(ID(x)); } } scanf("%d", &NI); kase++; for(int trip = 1; trip <= NI; trip++) { iti.clear(); scanf("%d", &len); for(int i = 0; i < len; i++) { scanf("%d", &x); iti.push_back(ID(x)); } solver.init(n_cities * len); for(int ticket = 0; ticket < NT; ticket++) for(int visited = 1; visited < len; visited++) { int cur = cities[ticket][0]; // 当前状态为(visited, cur) int next = visited; // 下一个需要访问的城市在iti中的下标 for(int leg = 1; leg < cities[ticket].size(); leg++) { // 使用前leg段 if(cities[ticket][leg] == iti[next]) next++; // 行程上多经过一个城市 solver.AddEdge(ID(visited, cur), ID(next, cities[ticket][leg]), cost[ticket], ticket+1); if(next == len) break; // 行程单已经走完 } } int src = ID(1, iti[0]), dest = ID(len, iti[len-1]); solver.dijkstra(src); printf("Case %d, Trip %d: Cost = %d ", kase, trip, solver.d[dest]); printf(" Tickets used:"); vector<int> path = solver.GetShortestPath(src, dest); for(int i = 0; i < path.size(); i++) printf(" %d", path[i]); printf(" "); } } return 0; }