链接:http://codeforces.com/contest/938/problem/D
题意: n个点 m 个边,并且每个点有个权值,你要对每个点求出 一个点j 使得dis[i,j]*2+a[j] 是最小的。
思路: 建立一个超级源点 S 从S 向每个点建一条边 边权为该点的点权,然后跑个dij 就是答案。 不难理解。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf =1e18+5;
typedef pair< ll,int > pli;
const int N = 2e5+5;
ll dis[N];
int vis[N];
ll a[N];
int n,m;
//int S;
vector< pli >ve[N];
void dij()
{
priority_queue< pli, vector<pli> ,greater< pli > >q;
for(int i=1;i<=n;i++)
{
dis[i]=a[i];
vis[i]=0;
q.push(pli(a[i],i));
}
while(!q.empty())
{
pli tmp=q.top(); q.pop();
int u=tmp.second;
if(tmp.first>dis[u]) continue;
vis[u]=1;
for(int i=0;i<ve[u].size();i++)
{
int v=ve[u][i].second;
if(vis[v]) continue;
if(dis[v]>dis[u]+ve[u][i].first)
{
dis[v]=dis[u]+ve[u][i].first;
q.push(pli(dis[v],v));
}
}
}
for(int i=1;i<=n;i++)
{
printf("%lld ",dis[i]);
}
}
void dij(int S)
{
for(int i=0;i<=n+2;i++)
{
dis[i]=inf;
vis[i]=0;
}
dis[0]=0;
priority_queue< pli, vector<pli>, greater<pli> >q;
q.push(pli(0,S));
while(!q.empty())
{
pli tmp=q.top(); q.pop();
int u=tmp.second;
if(tmp.first>dis[u]) continue;
vis[u]=1;
for(int i=0;i<ve[u].size();i++)
{
int v=ve[u][i].second;
if(vis[v]) continue;
if(dis[v]>dis[u]+ve[u][i].first)
{
dis[v]=dis[u]+ve[u][i].first;
q.push(pli(dis[v],v));
}
}
}
for(int i=1;i<=n;i++)
{
printf("%lld ",dis[i]);
}
}
int main()
{
int u,v; ll w;
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d %d %lld",&u,&v,&w);
ve[u].push_back(pli(w*2,v));
ve[v].push_back(pli(w*2,u));
}
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
ve[0].push_back(pli(a[i],i));
}
dij(0);
return 0;
}