題目大意:
給定n,m,k:n個點,m條邊,要進行刪邊操作,最後可以保留最多k條邊
定義一個點i是好的當且僅當在刪除一些邊之後,1->i的最短路等於未刪邊之前的最短路
輸出最多可以有多少個好的點,輸出保留邊的個數與保留邊的編號
題目思路:
剛開始看到刪邊,聯想到最短路徑還原。
考慮求最短路的過程,可以知道求最短路的過程中一定會存在沒有用的一些邊即對最短路根本沒有影響的邊。
如果對於一條邊來說滿足:dis[s]+w = = dis[e] ,那麼s這條邊在1 -> e的最短路上
所以首先把不滿足這個條件的邊刪掉
之後考慮剩下的邊,顯然可見最短路是分層的:
此時,顯而易見肯定從後向前刪,因爲刪除過程中的一下子會失去大於等於1個點,而刪最後只會失去一個點。
考慮一下拓撲排序或許可以解決這個問題。
但是呢考慮這個邊權都是正數,起點又固定,所以最短路按分層來說絕對是距離越來越大,所以只需要排序,保留前k個點即可
wa7..
又隨便考慮一下這個問題,發現有一種情況:
基於上面的圖,或許會還原出這種情況:
此時刪除點4以爲刪除2條邊,所以可能會出錯。
所以去重一下,每一個點只對應一條邊,現在來說就可以一個點對應一個權值,然後排序之後保留前k個點,也就保留了前k條邊。
注意:
1.這個題因爲是d2的,所以絕對有不法份子專門卡spfa【賽時hack機制】,所以建議優化的最短路
2.親測最短路的值爆了long long
Code:
/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll INF=1e17;
const int maxn=1e6+6;
const int mod=998244353;
const double eps=1e-3;
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
struct node{
int s,e,next;
ll w;
}edge[maxn];
ll cnt = 0;
int head[maxn];
void addedge(int u,int v,ll w){
edge[cnt]=node{u,v,head[u],w};
head[u]=cnt++;
}
ll dis[maxn];
struct N{
int id;
ll w;
bool friend operator<(N a,N b)
{
return a.w>b.w;
}
};
void dijstra(int st)
{
for(int i=1;i<=n;i++) dis[i]=INF;
dis[st]=0;
N s;s.id=st;s.w=0;
priority_queue<N>q;
q.push(s);
while(!q.empty())
{
N u=q.top();q.pop();
if(dis[u.id]!=u.w) continue;
for(int i=head[u.id];~i;i=edge[i].next)
{
int e=edge[i].e;
if(dis[e]>u.w+edge[i].w)
{
dis[e]=u.w+edge[i].w;
N now;now.id=e;
now.w=dis[e];
q.push(now);
}
}
}
}
pair<ll,int>save[maxn];
int visp[maxn];
ll res=0;
void rebuild(){
for(int i=0;i<cnt;i++)
if(dis[edge[i].s]+edge[i].w==dis[edge[i].e]&&!visp[edge[i].e]){
save[++res]={dis[edge[i].e],i/2+1};
visp[edge[i].e]=1;
}
}
int main(){
memset(head,-1,sizeof(head));
read(n);read(m);read(p);
for(int i=1;i<=m;i++){
int x,y;ll w;
scanf("%d%d%lld",&x,&y,&w);
addedge(x,y,w);
addedge(y,x,w);
}
dijstra(1);
rebuild();
if(p>=res){
printf("%lld\n",res);
for(int i=1;i<=res;i++)
printf("%d ",save[i].second);
}
else{
printf("%lld\n",p);
sort(save+1,save+1+res);
for(int i=1;i<=p;i++)
printf("%d ",save[i].second);
}
printf("\n");
return 0;
}
/**
4 5 3
4 1 8
2 4 1
2 1 3
3 4 9
3 1 5
**/