题目:
传送门
题意:
给出n个点,m条边,要求图中最多有k条边的前提下,生成尽可能多的good点。good点:删除一些边和没删除前从1到good点的最短路径是一样的。
思路:
先求出各个点的最短路径,记录下每个点的前驱,然后走一遍bfs,将符合条件的边的序号加入vector中。
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
const int maxn=3*1e5+5;
typedef long long ll;
const ll INF=1e15;
int n,m,k;
int head[maxn];
ll d[maxn];
int pre[maxn];
vector<int>ans;
struct Node
{
int v;
ll dis;
bool operator < (const Node x) const
{
return dis > x.dis;
}
};
struct edge
{
int to;
ll w;
int next;
}edge[maxn<<1];
void addedge (int u,int v,ll w,int id)
{
edge[id].to=v;
edge[id].w=w;
edge[id].next=head[u];
head[u]=id;
}
void djst ()
{
int vis[maxn];
for (int i=1;i<=n;i++)
{
vis[i]=0;
d[i]=INF;
}
d[1]=0;
priority_queue<Node>q;
Node t;
t.v=1; t.dis=0;
q.push(t);
while (!q.empty())
{
Node t=q.top();
q.pop();
int u=t.v; ll dis=t.dis;
if(vis[u])
continue;
vis[u]=1;
for (int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(!vis[v]&&d[u]+edge[i].w<d[v])
{
d[v]=d[u]+edge[i].w;
pre[v]=u;
Node x; x.v=v; x.dis=d[v];
q.push(x);
}
}
}
}
void bfs ()
{
queue<int>q;
q.push(1);
while (!q.empty())
{
int t=q.front();
q.pop();
for (int i=head[t];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(pre[v]==t&&ans.size()<k)
{
q.push(v);
ans.push_back(i/2+1);
}
}
if(ans.size()>=k)
break;
}
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
int id=0;
memset (pre,-1,sizeof(pre));
memset (head,-1,sizeof(head));
for (int i=0;i<m;i++)
{
int x,y;
ll w;
scanf("%d%d%lld",&x,&y,&w);
addedge(x,y,w,id++);
addedge(y,x,w,id++);
}
djst();
bfs();
printf("%d\n",ans.size());
for (int i=0;i<ans.size();i++)
{
printf("%d%c",ans[i],i==ans.size()-1?'\n':' ');
}
return 0;
}