题目
给你一个有n个顶点、m条边的无向带权图。需要擦除一些边使得剩余的边数不超过k,如果一个点在原始图到顶点1的最短距离为d,在删边后的图中到顶点的最短距离仍是d,则称这种点是 good。问如何删边,使得 good点最多。
分析
首先调用最短路算法求各点到顶点1的最短距离,同时记录下每点在最短路上的前一个顶点。然后从顶点1出发搜索一个大小为k的联通块即可(如果够k个)
代码
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #include<queue> 5 #include<algorithm> 6 using namespace std; 7 8 typedef long long ll; 9 10 const ll INF = (ll)1 << 61; 11 const int maxv = 300000 + 10; //最大顶点数 12 const int maxe = 300000 * 2+ 10; //最大边数 13 ll dis[maxv]; //源到各顶点的最短距离 14 int vis[maxv]; //记录是否被收录,用来代替集合S 15 int head[maxv]; //采用链式前向星建图 16 int pre[maxv]; //最短路树,记录前一个节点 17 18 vector<int>ans; //记录答案 19 int n, m, k; //顶点数、边数、最大保留的边数 20 21 struct Node 22 { 23 int u; 24 ll d; //该节点的编号与距离 25 bool operator < (const Node x) const 26 { 27 return d > x.d; 28 } 29 }; 30 31 struct Edge 32 { 33 int to, w, next; 34 }edge[maxe]; 35 36 37 inline void addedge(int u, int v, int w, int id) 38 { 39 edge[id].to = v; 40 edge[id].w = w; 41 edge[id].next = head[u]; 42 head[u] = id; 43 } 44 //s为起点 45 void Dijsktra(int s) 46 { 47 priority_queue<Node>q; //取出集合T中的最小值 48 memset(vis, 0, sizeof(vis)); 49 memset(pre, -1, sizeof(pre)); 50 //memset(dis, INF, sizeof(dis)); //与邻接矩阵不同,这里初始化为INF就可以,原因自己想 51 for (int i = 0; i <= n; i++) dis[i] = INF; 52 53 dis[s] = 0; 54 q.push(Node{ s, dis[s] }); 55 while (!q.empty()) 56 { 57 Node x = q.top(); q.pop(); 58 int u = x.u; 59 60 if (vis[u]) continue; 61 62 vis[u] = true; 63 for (int i = head[u]; i != -1; i = edge[i].next) //松弛与u直接相邻的顶点 64 { 65 int v = edge[i].to; 66 int w = edge[i].w; 67 if (!vis[v] && dis[u] + w < dis[v]) 68 { 69 dis[v] = dis[u] + w; 70 pre[v] = u; //记录最短路树的父节点 71 q.push(Node{ v,dis[v] }); 72 } 73 } 74 } 75 } 76 77 //从s出发找出最短路树上的k个节点(不到k个就是全部节点) 78 void bfs(int s) 79 { 80 queue<int>q; 81 q.push(s); 82 while (!q.empty()) 83 { 84 int u = q.front(); q.pop(); 85 for (int e = head[u]; e != -1; e = edge[e].next) 86 { 87 int v = edge[e].to; 88 if (pre[v] == u && ans.size() < k) 89 { 90 q.push(edge[e].to); 91 ans.push_back(e / 2 + 1); //无向边建图时存了两遍,真实序号位e/2+1 92 } 93 } 94 if (ans.size() >= k) break; 95 } 96 } 97 98 int main() 99 { 100 while (scanf("%d%d%d",&n,&m,&k) == 3) 101 { 102 memset(head, -1, sizeof(head)); 103 int id = 0; 104 for (int i = 0; i < m; i++) 105 { 106 int u, v, w; 107 scanf("%d%d%d", &u, &v, &w); 108 addedge(u, v, w,id++); addedge(v, u, w,id++); 109 } 110 111 Dijsktra(1); 112 113 ans.clear(); 114 bfs(1); 115 int cnt = ans.size(); 116 printf("%d\n", cnt); 117 for (int i = 0; i < cnt; i++) 118 printf("%d%c", ans[i], i == cnt - 1 ? '\n' : ' '); 119 } 120 return 0; 121 }