<题目链接>
题目大意:
n个点,m条边的无向图,现在需要删除一些边,使得剩下的边数不能超过K条。1点为起点,如果1到 i 点的最短距离与删除边之前的最短距离相同,则称 i 为 "good vertice",现在问你如果要使 "good vertice"最多,需要留下多少条边,并且输出这些边的序号。
解题分析:
我们最多只能留k条边 (或者是n-1条边,因为经过Dijkstra松弛后,其实只需要n-1条边就能使起点到所有点的最短距离仍然为未删边时的最短距离,想一下Dijkstra的松弛过程就能明白)。
那如何留下的 "good vertice" 最多呢?其实 "good vertice" 就是指我们尽量不要破坏原来的最短路径,那些越先通过Dijkstra松弛得到最短路的点的最短路径所需的维护的路径数量是最少的,所以我们贪心的将松弛的前K个点的之前的路劲记录即可,这样延伸出的连通块能够让其中所有的点到起点的最短距离等于原始的最短距离,同时他们所需维护的路径还是尽可能的少的。
1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 #include <vector> 5 #include <algorithm> 6 using namespace std; 7 8 #define M int(3e5+10) 9 #define rep(i,s,t) for(int i=s;i<=t;i++) 10 #define pb push_back 11 #define clr(a,b) memset(a,b,sizeof(a)) 12 #define INF ll(1e18) 13 typedef long long ll; 14 int cnt,head[M],loc[M]; 15 bool vis[M]; 16 vector<int>vec; 17 int n,m,k; 18 19 template<typename T> 20 inline T read(T&x){ 21 x=0;int f=0;char ch=getchar(); 22 while (ch<'0' || ch>'9') f|=(ch=='-'),ch=getchar(); 23 while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar(); 24 return x=f?-x:x; 25 } 26 struct Edge{ 27 int to,ord,next; 28 ll val; 29 }edge[M<<1]; 30 31 struct Node{ 32 int ord;ll dist; 33 Node(int _ord=0,ll _dist=0):ord(_ord),dist(_dist){} 34 bool operator < (const Node &tmp)const { 35 return dist>tmp.dist; 36 } 37 }d[M]; 38 void init(){ 39 cnt=0;clr(head,-1); 40 } 41 void addedge(int u,int v,ll w,int c){ 42 edge[++cnt].to=v;edge[cnt].val=w,edge[cnt].ord=c; 43 edge[cnt].next=head[u];head[u]=cnt; 44 } 45 void Dijkstra(){ 46 priority_queue<Node>q; 47 for(int i=1;i<=n;i++) 48 d[i].dist=INF,d[i].ord=i,vis[i]=false; 49 d[1].dist=0;q.push(d[1]); 50 while(q.size()){ 51 int u=q.top().ord;q.pop(); 52 if(vis[u])continue; 53 vis[u]=true;vec.pb(loc[u]); 54 if(vec.size()==k+1)return ; //因为起点的前一条边没有意义,所以这里是k+1结束 55 for(int i=head[u];~i;i=edge[i].next){ 56 int v=edge[i].to;ll cost=edge[i].val; 57 if(!vis[v]&&d[v].dist>d[u].dist+cost){ 58 d[v].dist=d[u].dist+cost; 59 loc[v]=edge[i].ord; //记录这个点在 1--->v的最短路的最后一条边 60 q.push(d[v]); 61 } 62 } 63 } 64 } 65 int main(){ 66 read(n);read(m);read(k);init(); 67 rep(i,1,m){ 68 int u,v;ll w; 69 read(u);read(v);read(w); 70 addedge(u,v,w,i);addedge(v,u,w,i); 71 } 72 k=min(k,n-1); //k与(n-1)进行比较 73 Dijkstra();printf("%d ",k); 74 rep(i,1,k)i==k?printf("%d ",vec[i]):printf("%d ",vec[i]); //因为起点的前一条边没有意义,所以这里从1开始输出 75 }
2019-02-12