题意:
给你n个点m条边的无向图,其中1号节点是市中心,你现在最多只能保留k条边,并要求所有点到市中心的最短路尽量不变(也就是说设点i到点1的最短路为di,那么删边之后,要保证尽可能多的点,它到1的最短路仍然是di),求保留哪k条边,当然你可以保留<k条边就是了
思路:
对于每个点u,一定存在last[u]表示从1到u的走最短路,上一个点是哪个点,当然可能不唯一,不过无所谓
这样求一遍1到所有点的最短路之后,对于每个点u,last[u]向u连一条边,这样可以得到一棵最短路树
然后保留最短路树上的边就行了
就这么简单,不过求最短路的时候尽量不要用SPFA,因为它可能被卡到O(nm)
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<string>
#include<math.h>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
#define LL long long
#define mod 1000000007
typedef struct Road
{
LL len;
int x, y, id;
bool operator < (const Road &b) const
{
if(len>b.len)
return 1;
return 0;
}
}Road;
vector<Road> G[300005], F[300005];
LL dp[300005], ans[300005];
int last[300005], vis[300005], k;
priority_queue<Road> q;
void Sech(int u)
{
int i, v;
for(i=0;i<F[u].size();i++)
{
v = F[u][i].y;
if(k>=1)
{
printf("%d ", F[u][i].id);
k--;
}
Sech(v);
}
}
int main(void)
{
Road now, temp;
int x, y, n, m, i, v;
scanf("%d%d%d", &n, &m, &k);
memset(dp, -1, sizeof(dp));
for(i=1;i<=m;i++)
{
scanf("%d%d%lld", &x, &y, &now.len), now.id = i;
now.x = x, now.y = y, G[x].push_back(now);
now.x = y, now.y = x, G[y].push_back(now);
}
dp[1] = last[1] = 0;
for(i=0;i<G[1].size();i++)
{
q.push(G[1][i]);
vis[G[1][i].id] = 1;
}
while(q.empty()==0)
{
now = q.top();
q.pop();
if(dp[now.y]==-1)
{
dp[now.y] = now.len;
last[now.y] = now.x;
F[now.x].push_back(now);
for(i=0;i<G[now.y].size();i++)
{
v = G[now.y][i].y;
temp.x = now.y, temp.y = v, temp.id = G[now.y][i].id;
if(vis[temp.id]==0)
{
temp.len = G[now.y][i].len+dp[now.y];
q.push(temp);
vis[temp.id] = 1;
}
}
}
}
if(k>=n-1)
k = n-1;
printf("%d\n", k);
Sech(1);
printf("\n");
return 0;
}