题意:给一张图,每个点有一个weight,每一条边有一个weight,定义一个点到到另一个点的value是,2*dist(i,j)+weight[j],求每一个点的最小weight。
题解:我们可以把所有点当成起点,加入优先队列中跑,并且每个点的初始值为weight[i],然后跑Dijkstra,得到的所有答案,就是以每一个点为起点到其他点的最小值。
一开始我想通过将点分为两类,起点和终点,然后把起点的一半变为终点,终点的一半变为起点,然后跑logn遍dij,所以复杂度是O(logn*logn*n)的复杂度,但是TLE了,但是这种方法主要用于点到自己的距离不影响答案的时候使用,这道题不影响所以可以直接将所有点放入队列中。
注意:spfa在这里复杂度有点迷,一直过不去。
AC代码:
#include<stdio.h>
#include<vector>
#include<queue>
#define inf 2000000000000000000ll
using namespace std;
typedef long long ll;
struct node
{
ll to,w;
node(){}
node(ll to,ll w)
{
this->to=to;
this->w=w;
}
};
vector<node>vt[200005];
ll a[200005],dist[200005],mark[200005],n,m;
priority_queue<node>que;
bool operator<(node a,node b)
{
return a.w>b.w;
}
void dij()
{
for(ll i=1;i<=n;i++)
dist[i]=a[i],mark[i]=0,que.push(node(i,dist[i]));
while(!que.empty())
{
node k=que.top();
que.pop();
if(mark[k.to])continue;
mark[k.to]=1;
for(int i=0;i<vt[k.to].size();i++)
{
int to=vt[k.to][i].to;
if(mark[to]==0&&dist[to]>k.w+vt[k.to][i].w)
{
dist[to]=k.w+vt[k.to][i].w;
que.push(node(to,dist[to]));
}
}
}
}
int main()
{
scanf("%lld%lld",&n,&m);
for(ll i=0;i<m;i++)
{
ll u,v,w;
scanf("%lld%lld%lld",&u,&v,&w);
vt[u].push_back(node(v,w*2));
vt[v].push_back(node(u,w*2));
}
for(ll i=1;i<=n;i++)
scanf("%lld",&a[i]);
dij();
for(ll i=1;i<=n;i++)
printf("%lld ",dist[i]);
printf("\n");
}