NC16036. 你的城市
描述
输入描述
第一行,两个正整数n, m。n表示城市数量,m表示当天不同班次的火车数量。
接下来m行,每行3个整数x, y, c加两个字符串ts, td,均以空格作为分隔,表示当天的某一班火车。其中x, y, c, ts, td的含义如前描述。
所有的车次都是当天的,没有隔夜的票。
2 <= n <= 500, m <= 15000, c <= 1000, ts < td,所有数均为正整数。
车次保证不过夜,时间范围0:00, 0:30, 1:00, … , 23:00, 23:30, 24:00,可能存在重复车次。
输出描述
一个整数,表示存在补救措施的前提下,小A到达C城的最小花费。如果不存在这样的路径,则输出-1。
示例1
输入:
3 5 1 3 800 18:00 21:00 1 2 650 13:30 14:00 2 3 100 14:00 18:00 2 3 300 14:30 19:00 2 3 200 15:00 19:30
输出:
950
说明:
选择第二个和第四个车次。示例2
输入:
3 5 1 2 1000 0:00 12:00 1 2 100 0:30 14:00 1 2 100 0:30 15:00 2 3 300 16:00 24:00 2 3 200 16:30 24:00
输出:
1300
说明:
选择第一个和第四个车次。示例3
输入:
3 4 1 2 100 0:30 14:00 1 2 200 0:30 15:00 2 3 300 16:00 24:00 2 3 200 16:30 24:00
输出:
-1
说明:
和样例二类似,但是缺少了原先的车次一,所以没有换乘方案。示例4
输入:
3 4 1 2 100 0:30 14:00 1 2 200 1:00 16:00 2 3 300 16:00 24:00 2 3 200 16:30 24:00
输出:
400
说明:
选择第一个和第三个车次。示例5
输入:
3 4 1 2 100 0:30 14:00 1 2 200 1:00 16:30 2 3 300 16:00 24:00 2 3 200 16:30 24:00
输出:
-1
说明:
和样例四类似,但假如错过了第一个车次,改乘车次二在16:30到达城市2是不足以赶上16:30出发的车次四的。C++11(clang++ 3.9) 解法, 执行用时: 50ms, 内存消耗: 18284K, 提交时间: 2018-07-07 20:20:16
#include <iostream> #include <cstring> #include <vector> #include <queue> using namespace std; const int INF = 0x3f3f3f3f; const int MAXN = 5e5 + 10; const int MAGIC = 49; struct node { int v, c; node(int v_ = 0, int c_ = 0) : v(v_), c(c_) {} bool operator < (const node &r)const { return c > r.c; } }; struct edge { int v, cost; edge(int v_ = 0, int cost_ = 0) : v(v_), cost(cost_) {} }; int n, m; int dis[MAXN]; int cnt[MAXN]; bool vis[MAXN]; vector<edge> E[MAXN]; void Dijkstra( int start) { memset(vis, false, sizeof(vis)); memset(dis, 0x3f, sizeof(dis)); priority_queue<node> pqn; dis[start] = 0; pqn.push(node(start, 0)); node tmp; while (!pqn.empty()) { tmp = pqn.top(); pqn.pop(); int u = tmp.v; // 保证有补救措施 if (!cnt[u + 1]) { continue; } if (vis[u]) { continue; } vis[u] = true; for (int i = 0; i < E[u].size(); i++) { int v = E[tmp.v][i].v; int cost = E[u][i].cost; if (!vis[v] && dis[v] > dis[u] + cost) { dis[v] = dis[u] + cost; pqn.push(node(v, dis[v])); } } } } void addedge(int u, int v, int w) { E[u].push_back(edge(v, w)); } bool dfs(int u) { if (u == n * MAGIC + 2) { return cnt[u] = 1; } int flag = 0; size_t sz = E[u].size(); for (int i = 0; i < sz; i++) { int v = E[u][i].v; if (!vis[v]) { vis[v] = 1; if (dfs(v)) { flag = 1; } } else { if (cnt[v]) { flag = 1; } } } return cnt[u] = flag; } int main() { scanf("%d%d", &n, &m); int x, y, c, ts_h, ts_m, td_h, td_m; for (int i = 1; i <= m; i++) { scanf("%d%d%d%d:%d%d:%d", &x, &y, &c, &ts_h, &ts_m, &td_h, &td_m); // 拆点,半小时一个点,先拆做 MAGIC 个点 int ts_id = ts_h * 2 + (ts_m / 30) + 1; int td_id = td_h * 2 + (td_m / 30) + 1; // 如果某站直达终点则不需要考虑延时半小时 for (int j = td_id + (y == n ? 0 : 1); j <= MAGIC; j++) { addedge((x - 1) * MAGIC + ts_id, (y - 1) * MAGIC + j, c); } } // n * MAGIC + 1 号点为源点,在任何时刻由源点到达北京代价为 0 // n * MAGIC + 2 号点为汇点,在任何时刻由小城到达汇点代价为 0 for (int i = 1; i <= MAGIC; i++) { addedge(n * MAGIC + 1, i, 0); addedge((n - 1) * MAGIC + i, n * MAGIC + 2, 0); } // 从源点开始搜索 vis[n * MAGIC + 1] = 1; dfs(n * MAGIC + 1); for (int i = 1; i <= n; i++) { for (int j = MAGIC; j >= 1; j--) { cnt[(i - 1) * MAGIC + j] += cnt[(i - 1) * MAGIC + j + 1]; } } memset(vis, 0, sizeof(vis)); Dijkstra( n * MAGIC + 1); if (dis[n * MAGIC + 2] == INF) { cout << "-1\n"; } else { cout << dis[n * MAGIC + 2] << "\n"; } return 0; }
C++14(g++5.4) 解法, 执行用时: 30ms, 内存消耗: 1248K, 提交时间: 2018-06-18 19:53:16
#include<cstdio> #include<cstdlib> #include<string> #include<algorithm> #define For(i,l,r) for(int i=l;i<=r;i++) #define Dor(i,r,l) for(int i=r;i>=l;i--) #define timeMagicNumber 49 #define inf 100000000 using namespace std; char convert_buffer[10]; int convert(char* buffer){ int a,b; sscanf(buffer,"%d:%d",&a,&b); return a*2 + b / 30; } char* convert(int num){ sprintf(convert_buffer, "%d:%02d", num/2, (num&1)*30); return convert_buffer; } struct Edge{ int x,y,co,s,t; void read(){ scanf("%d%d%d",&x,&y,&co); scanf("%s",convert_buffer); s = convert(convert_buffer); scanf("%s",convert_buffer); t = convert(convert_buffer); } }E[200005]; int n,m; int cnt; int son[200005],Next[500005],ed[500005],edge_cost[500005],edge_s[500005],edge_t[500005]; void graph_link(int x,int y,int c,int s,int t){ Next[++cnt] = son[x]; son[x]=cnt; ed[cnt]=y; edge_cost[cnt] = c; edge_s[cnt] = s; edge_t[cnt] = t; } int f[2005][55],ff[200005]; int dist[2005][55]; int dfs(int u,int ut){ if (f[u][ut] == 1) return 1; if (f[u][ut] == 0) return 0; if (ut == timeMagicNumber) return 0; f[u][ut] = 0; for(int i=son[u];i;i=Next[i]) if(edge_s[i] == ut){ f[u][ut] |= dfs(ed[i],edge_t[i]+1); } f[u][ut] |= dfs(u,ut+1); return f[u][ut]; } void dfs(int u,int ut,int di){ if (di >= dist[u][ut]) return; dist[u][ut] = di; if (u == n) return; if (ut == timeMagicNumber) return; if (ut >= ff[u]) return; dfs(u,ut+1,di); for(int i=son[u];i;i=Next[i]) if(edge_s[i] == ut){ dfs(ed[i],edge_t[i]+1,edge_cost[i]+di); } } int main(){ scanf("%d%d",&n,&m); For(i,1,m) E[i].read(); For(i,1,m) graph_link(E[i].x,E[i].y,E[i].co,E[i].s,E[i].t); For(i,1,n-1) For(t,0,timeMagicNumber) f[i][t] = -1,f[n][t] = 1; For(i,1,n-1) For(t,0,timeMagicNumber-1) dfs(i,t); For(i,1,n) For(t,0,timeMagicNumber) if(f[i][t] == 1) ff[i] = t; For(i,1,n) For(t,0,timeMagicNumber) dist[i][t] = inf; dfs(1,0,0); int ans = inf; For(nt,0,timeMagicNumber) ans = min(ans,dist[n][nt]); if (ans == inf) ans = -1; printf("%d\n",ans); }
Python3(3.5.2) 解法, 执行用时: 1097ms, 内存消耗: 29116K, 提交时间: 2018-06-18 20:15:56
import sys line = sys.stdin.readline().strip() values = list(map(int, line.split())) n, m = values[0], values[1] cost, start, end = {}, {}, {} N, cnt = 49, 1 son, Next = [0 for _ in range(200005)], [0 for _ in range(500005)] ed, edge_cost, edge_s, edge_t = Next.copy(), Next.copy(), Next.copy(), Next.copy() for k in range(m): values = sys.stdin.readline().strip().split() # i, j = int(values[0]), int(values[1]) # cost[(i,j)] = int(values[2]) # start[(i,j)] = int(values[3][:2]) * 2 + int(int(values[3][3:]) / 30) # end[(i,j)] = int(values[4][:2]) * 2+ int(int(values[4][3:]) / 30) Next[cnt] = son[int(values[0])] son[int(values[0])] = cnt ed[cnt] = int(values[1]) edge_cost[cnt] = (int(values[2])) mid = values[3].split(":") edge_s[cnt] = (int(mid[0]) * 2 + int(int(mid[1]) / 30)) mid = values[4].split(":") edge_t[cnt] = (int(mid[0]) * 2 + int(int(mid[1]) / 30)) cnt += 1 def dfs1(u, ut): if f[u][ut] == 1: return 1 if f[u][ut] == 0: return 0 if ut == N: return 0 f[u][ut] = 0 i = son[u] while i: if edge_s[i] == ut: f[u][ut] |= dfs1(ed[i], edge_t[i] + 1) f[u][ut] |= dfs1(u, ut+1) i = Next[i] return f[u][ut] def dfs2(u, ut, di): if di >= dist[u][ut]: return dist[u][ut] = di if u == n: return if ut == N: return if ut >= ff[u]: return dfs2(u, ut+1, di) i = son[u] while i: if edge_s[i] == ut: dfs2(ed[i], edge_t[i] + 1, edge_cost[i] + di) i = Next[i] f = [[0 for _ in range(55)] for _ in range(2005)] ff = [0 for _ in range(200005)] dist = [[0 for _ in range(55)] for _ in range(2005)] for i in range(1, n): for t in range(0, N+1): f[i][t] = -1 for t in range(0, N+1): f[n][t] = 1 for i in range(1, n): for t in range(0, N): dfs1(i, t) for i in range(1, n+1): for t in range(0, N+1): if f[i][t] == 1: ff[i] = t for i in range(1, n+1): for t in range(0, N+1): dist[i][t] = 100000000 dfs2(1, 0, 0) ans = 100000000 for nt in range(0, N+1): ans = min(ans, dist[n][nt]) if (ans == 100000000): ans = -1 print(ans)