【洛谷P1828】香甜的黃油
阿新 • • 發佈:2019-01-12
題目大意:給定 N 個點,M 條邊的無向圖,在其中選定 P 個點,每個點可能被選多次,求圖中的一個點到選定的 P 個點的距離的值最小是多少。
題解:由於資料範圍的限制,直接 Floyd 會超時,因此對每個點做一次堆優化的 dij,統計答案貢獻後更新答案即可。
程式碼如下
#include <bits/stdc++.h> #define mp make_pair using namespace std; typedef pair<int,int> P; const int maxn=810; inline int read(){ int x=0,f=1;char ch; do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch)); do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch)); return f*x; } struct node{ int nxt,to,w; }e[maxn<<2]; int tot=1,head[maxn]; inline void add_edge(int from,int to,int w){ e[++tot]=node{head[from],to,w},head[from]=tot; } int num,n,m,pos[maxn],d[maxn]; bool vis[maxn]; priority_queue<P> q; void read_and_parse(){ num=read(),n=read(),m=read(); for(int i=1;i<=num;i++)pos[i]=read(); for(int i=1,x,y,z;i<=m;i++){ x=read(),y=read(),z=read(); add_edge(x,y,z),add_edge(y,x,z); } } void dij(int st){ memset(d,0x3f,sizeof(d)); memset(vis,0,sizeof(vis)); d[st]=0,q.push(mp(0,st)); while(q.size()){ int u=q.top().second;q.pop(); if(vis[u])continue; vis[u]=1; for(int i=head[u];i;i=e[i].nxt){ int v=e[i].to,w=e[i].w; if(d[u]+w<d[v])d[v]=d[u]+w,q.push(mp(-d[v],v)); } } } void solve(){ int ans=0x3f3f3f3f; for(int i=1;i<=n;i++){ dij(i); int tmp=0; for(int i=1;i<=num;i++)tmp+=d[pos[i]]; ans=min(ans,tmp); } printf("%d\n",ans); } int main(){ read_and_parse(); solve(); return 0; }