题目大意:美国佬打算入侵火星,火星上有n个城市,有些城市可能受其他城市保护,
如果i城市受j城市保护,那么你必须先攻占j城市才能再攻占i城市,问你攻占城市n的最短时间是多少。
数据解释:
给定t, 表示有t组数据
给定n,m 表示n个点,m条边
接下来m条有向边, a,b,c 表示从a到b,距离为c
接下来n行, 每行第一个整数d,然后接下来是d个整数,x1,x2,...xd, 表示第i个城市受d个城市保护,表示只有城市x1,x2...xd都被攻占,城市i才能被攻占
问从点1到达点n的最短时间(一定是可达的)
重要的一点是,因为是军队,所以可以同时进军多个点。
思路:
如果城市i受其他城市保护, 那么攻占城市i的最短时间是从1-->i和攻占城市i的保护城市 这两个时间中的最大值。
设dist[i] 为 攻占城市i的最短时间, maxn[i] 为攻占所有保护i的城市中时间最长的那个
那么 dist[i] = max(dist[i],maxn[i])
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <algorithm> 5 #include <iostream> 6 #include <queue> 7 #include <stack> 8 #include <vector> 9 #include <map> 10 #include <set> 11 #include <string> 12 #include <math.h> 13 using namespace std; 14 #pragma warning(disable:4996) 15 typedef long long LL; 16 const int INF = 1 << 30; 17 /* 18 19 */ 20 struct Edge 21 { 22 int to, dist; 23 bool operator<(const Edge&rhs)const 24 { 25 return dist > rhs.dist; 26 } 27 }; 28 vector<Edge> g[3000 + 10]; 29 vector<int> pro[3000 + 10]; 30 bool vis[3000 + 10]; 31 int protect[3000 + 10]; 32 int dist[3000 + 10], maxn[3000 + 10], ans[3000 + 10]; 33 void dij(int n) 34 { 35 for (int i = 1; i <= n; ++i) 36 { 37 vis[i] = false; 38 dist[i] = INF; 39 maxn[i] = 0; 40 } 41 dist[1] = 0; 42 priority_queue<Edge> q; 43 Edge cur, tmp; 44 cur.to = 1; 45 cur.dist = 0; 46 q.push(cur); 47 while (!q.empty()) 48 { 49 cur = q.top(); q.pop(); 50 int x = cur.to; 51 if (vis[x]) continue; 52 for (int i = 0; i < pro[x].size(); ++i) 53 { 54 int v = pro[x][i]; 55 maxn[v] = max(maxn[v], dist[x]);//求出到达保护城市v的城市最长的那一个 56 protect[v]--; 57 } 58 vis[x] = true; 59 for (int i = 0; i < g[x].size(); ++i) 60 { 61 int v = g[x][i].to; 62 if (dist[v] > dist[x] + g[x][i].dist) 63 dist[v] = dist[x] + g[x][i].dist; 64 } 65 for (int i = 1; i <= n; ++i) 66 { 67 if (vis[i]) continue; 68 dist[i] = max(dist[i], maxn[i]); 69 if (protect[i] == 0 && dist[i]!=INF)//在点i没有解除约束之前,我们不能让它去更新其它的点 70 { 71 tmp.to = i; 72 tmp.dist = dist[i]; 73 q.push(tmp); 74 } 75 76 } 77 } 78 } 79 80 void input(int &x) 81 { 82 char ch = getchar(); 83 while (ch > '9' || ch < '0') 84 ch = getchar(); 85 x = 0; 86 while (ch >= '0' && ch <= '9') 87 { 88 x = x * 10 + ch - '0'; 89 ch = getchar(); 90 } 91 } 92 int main() 93 { 94 int t, n, m, i, a, b, c; 95 Edge tmp; 96 scanf("%d", &t); 97 while (t--) 98 { 99 //scanf("%d%d", &n, &m); 100 input(n); input(m); 101 for (i = 1; i <= n; ++i) 102 { 103 g[i].clear(); 104 pro[i].clear(); 105 } 106 for (i = 0; i < m; ++i) 107 { 108 //scanf("%d%d%d", &a, &b, &c); 109 input(a); input(b); input(c); 110 tmp.to = b; 111 tmp.dist = c; 112 g[a].push_back(tmp); 113 } 114 for (int i = 1; i <= n; ++i) 115 { 116 //scanf("%d", &a); 117 input(a); 118 protect[i] = a; 119 for (int j = 0; j < a; ++j) 120 { 121 //scanf("%d", &b); 122 input(b); 123 pro[b].push_back(i); 124 } 125 } 126 dij(n); 127 printf("%d ", dist[n]); 128 } 129 return 0; 130 }