• B. 看比赛 The 10th Jimei University Programming Contest


    Problem - B - Codeforces

    题目大意:有一个n的个点的无向边权图,A和B两个人要从1号点去往n号点,每一轮,他们会轮流选择下一步要走的一条边,然后两个人一起走过去,A先选,他们每次选的路一定是到1到n的最短路上的一条边,最后到n时轮到谁选就算谁输,问谁能赢

    2<=n<=1e5;2<=m<=2e5;1<=w[i]<=1e9

    思路:因为直走最短路,所以我们把所有在最短路上的边都要选出来,建成新图,为此,首先用dijkstra求出1到n的最短路的长度,然后我们从n开始bfs,遍历相邻边,如果这条边的边权加上1到这条边起点的最短路距离等于1到这条边终点的最短路距离,那么就把这条边加到新图中,最后就会形成一个包含1到n的所有最短路的DAG。

            然后考虑sg的转移,显然当他们在n点时,先手必败,令sg[n]=0,然后因为新图是无向图,所以按照常规树上博弈的方法转移,sg[u]=MEX(sg[v1],sg[v2]...),但因为不是树而是图,所以要记忆化一下,避免重复遍历

    1. #include
    2. //#include<__msvc_all_public_headers.hpp>
    3. using namespace std;
    4. typedef long long ll;
    5. const ll MOD = 1e9 + 7;
    6. const int N = 1e5 + 10, M = 2e5 + 10;
    7. const ll INF = 1e18;
    8. struct Edge
    9. {
    10. int u, v, next;
    11. ll w;
    12. }e[M*2];//链式前向星存图
    13. struct node
    14. {//优先队列中存储的点的编号和最短路
    15. int id;
    16. ll dis;
    17. bool operator<(const node& a)const
    18. {
    19. return dis > a.dis;
    20. }//因为我们要小的先出队,所以要把小于号重载为大于
    21. node(int a, ll b)
    22. {
    23. id = a, dis = b;
    24. }
    25. };
    26. int head[N], cnt = 0;
    27. void addedge(int u, int v, ll w)
    28. {//这里边的起点也要记录
    29. e[++cnt].v = v;
    30. e[cnt].u = u;
    31. e[cnt].w = w;
    32. e[cnt].next = head[u];
    33. head[u] = cnt;
    34. }
    35. int n, m;
    36. ll dis[N];
    37. bool done[N];
    38. ll fid;
    39. ll sg[N];
    40. set<int>ins;
    41. vector<int>g[N];
    42. bool vis[N];
    43. void bfs()
    44. {//建立新图
    45. queue<int>q;
    46. q.push(n);//从n开始bfs
    47. while (!q.empty())
    48. {
    49. int u = q.front();
    50. q.pop();
    51. if (vis[u])
    52. continue;
    53. vis[u] = 1;//避免重复遍历
    54. for (int i = head[u]; ~i; i = e[i].next)
    55. {
    56. int v = e[i].v;
    57. ll w = e[i].w;
    58. if (dis[v] + w == dis[u])
    59. {//这个边是想要的边
    60. g[v].push_back(u);
    61. q.push(v);
    62. }
    63. }
    64. }
    65. }
    66. void dijkstra()
    67. {
    68. int s = 1;
    69. for (int i = 1; i <= n; i++)
    70. {
    71. dis[i] = INF;//初始化到所有点的最短路为一极大值
    72. done[i] = 0;//判断每个点是否在集合A里
    73. }
    74. dis[s] = 0;
    75. priority_queueq;
    76. q.push(node(s, dis[s]));
    77. while (!q.empty())
    78. {
    79. node u = q.top();
    80. q.pop();
    81. if (done[u.id])
    82. {//已在集合A中的点说明已经找到最短路了
    83. continue;
    84. }
    85. done[u.id] = 1;
    86. for (int i = head[u.id]; ~i; i = e[i].next)
    87. {
    88. int v = e[i].v;
    89. ll w = e[i].w;
    90. if (done[v])
    91. {
    92. continue;
    93. }//避免回头访问到处理过的点
    94. if (dis[v] > w + u.dis)
    95. {
    96. dis[v] = w + u.dis;//维护最短路
    97. q.push(node(v, dis[v]));
    98. }
    99. }
    100. }
    101. }
    102. int dfs2(int u)
    103. {//求sg
    104. if (sg[u] != -1)
    105. {//记忆化
    106. return sg[u];
    107. }
    108. set<int>temp;
    109. for (int i = 0; i < g[u].size(); i++)
    110. {// 遍历子节点
    111. int v = g[u][i];
    112. temp.insert(dfs2(v));
    113. }
    114. int now = 0;
    115. for (set<int>::iterator it = temp.begin(); it != temp.end(); it++)
    116. {//找MEX
    117. if (*it == now)
    118. {
    119. now++;
    120. }
    121. else
    122. {
    123. sg[u] = now;
    124. return sg[u];;
    125. }
    126. }
    127. sg[u] = now;
    128. return sg[u];
    129. }
    130. void init()
    131. {
    132. cnt = 0;
    133. for (int i = 1; i <= n; i++)
    134. {
    135. head[i] = -1;
    136. g[i].clear();
    137. sg[i] = -1;
    138. vis[i] = 0;
    139. }
    140. ins.clear();
    141. }
    142. void solve()
    143. {
    144. cin >> n;
    145. init();
    146. cin >> m;
    147. for (int i = 1; i <= m; i++)
    148. {
    149. ll u, v, w;
    150. cin >> u >> v >> w;
    151. addedge(u, v, w);
    152. addedge(v, u, w);
    153. }
    154. dijkstra();
    155. fid = dis[n];
    156. bfs();
    157. sg[n] = 0;
    158. dfs2(1);
    159. if (!sg[1])
    160. {//sg=0这里表示先手必输
    161. cout << "Little I is the winner.\n";
    162. return;
    163. }
    164. cout << "Little M is the winner.\n";
    165. }
    166. int main()
    167. {
    168. ios::sync_with_stdio(false);
    169. cin.tie(0);
    170. int t;
    171. cin >> t;
    172. //t = 1;
    173. while (t--)
    174. {
    175. solve();
    176. }
    177. return 0;
    178. }
    179. //6 7
    180. //1 2 1
    181. //2 3 1
    182. //2 4 2
    183. //3 4 1
    184. //4 5 1
    185. //5 6 1
    186. //4 6 2
    187. //2 1
    188. //1 2 1
    189. //3 3
    190. //1 2 1
    191. //2 3 1
    192. //1 3 3
    193. //8 9
    194. //1 2 1
    195. //2 3 1
    196. //2 4 2
    197. //3 4 1
    198. //4 5 1
    199. //5 8 1
    200. //4 8 2
    201. //1 7 2
    202. //1 6 1

  • 相关阅读:
    Fragment之间进行通信的最佳实现方式
    05.大模型&大数据量
    写论文的步骤有没有?正确的顺序是什么?
    Python——序列_集合
    基于Java毕业设计智慧社区信息管理系统开发源码+系统+mysql+lw文档+部署软件
    MySQL篇---第五篇
    zemax双透镜公差分析
    Delving into Sample Loss Curve to Embrace Noisy and Imbalanced Data
    安科瑞餐饮油烟监测云平台助力大气污染防治攻坚战
    JUC P5 自定义线程池,线程池应用 基础+代码
  • 原文地址:https://blog.csdn.net/ashbringer233/article/details/134062349