1. 程式人生 > 實用技巧 >題解 CF545E 【Paths and Trees】

題解 CF545E 【Paths and Trees】

思路:

\(\quad\)只需要以題目給定的 \(u\) 為起點跑一遍 \(Dijkstra\) 最短路即可,每次記錄每個點的前驅(即到達這個點的邊),注意有多個可以選擇的邊中選擇邊權最小的,感覺很像一個最小生成樹,最後記得要記錄樹上的邊權並排序再輸出,起點 \(u\) 是沒有前驅的,所以要從 \(2\) 開始輸出。

\(\quad\)如果還不能理解就看看程式碼吧,有一些關鍵的註釋。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<cstring>
using namespace std;
#define re register int
#define int long long
#define LL long long
#define il inline
#define next nee
#define inf 1e18
il int read()
{
  int x=0,f=1;char ch=getchar();
  while(!isdigit(ch)&&ch!='-')ch=getchar();
  if(ch=='-')f=-1,ch=getchar();
  while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
  return x*f;
}
il void print(int x)
{
  if(x<0)putchar('-'),x=-x;
  if(x/10)print(x/10);
  putchar(x%10+'0');
}
const int N=3e5+5;
int n,m,next[N<<1],go[N<<1],head[N],tot,dis[N],s[N<<1],t,du[N],ans;
bool b[N];
il void Add(int x,int y,int z)
{
  next[++tot]=head[x];head[x]=tot;
  go[tot]=y;s[tot]=z;
}
struct node{
  int pos,dis;
  il bool operator<(const node &x)const
  {return dis>x.dis;}
};
priority_queue<node>q;
il void Dijkstra(int p)//板子Dijkstra
{
  for(re i=1;i<=n;i++)dis[i]=inf;dis[p]=0;
  q.push((node){p,0});
  while(!q.empty())
    {
      node tmp=q.top();q.pop();
      int x=tmp.pos;
      if(b[x])continue;
      b[x]=1;
      for(re i=head[x];i;i=next[i])
	{
	  int y=go[i];
	  if(dis[y]>dis[x]+s[i])
	    {
	      du[y]=i;//du記錄前驅編號為i的邊
	      dis[y]=dis[x]+s[i];
	      q.push((node){y,dis[y]});
	    }
	  else if(dis[y]==dis[x]+s[i])//有多條最短路徑時
	    {if(s[du[y]]>s[i])du[y]=i;}//選擇邊權小的
	}
    }
}
signed main()
{
  n=read();m=read();
  for(re i=1;i<=m;i++)
    {re x=read(),y=read(),z=read();Add(x,y,z);Add(y,x,z);}
  t=read();
  Dijkstra(t);
  for(re i=1;i<=n;i++)ans+=s[du[i]];//ans統計答案
  for(re i=1;i<=n;i++)dis[i]=du[i]+1>>1;
  sort(dis+1,dis+n+1);//別忘了排序
  print(ans);putchar('\n');
  for(re i=2;i<=n;i++)print(dis[i]),putchar(' ');//從2開始輸出
  return 0;
}