问题转换为对于每一个点x,求出一个点y,使得xy的最短路2倍+在y举办的费用最小。
考虑建一个超级源点,向每一个点连一条费用为其举办所需费用,并且原图中的边权值*2,跑一遍最短路,每一个点到超级源点的最短路即为答案。
卡spfa,请用dijkstra。
1 #include<bits/stdc++.h> 2 #define LL long long 3 using namespace std; 4 const int inf=2e5+10; 5 int n,m; 6 int tot,fi[inf],to[inf<<2],nxt[inf<<2]; 7 int s; 8 LL cost[inf<<2]; 9 void link(int x,int y,LL z){ 10 to[++tot]=y;nxt[tot]=fi[x];fi[x]=tot;cost[tot]=z; 11 } 12 LL dis[inf]; 13 struct dijk{ 14 int id; 15 LL val; 16 bool operator < (const dijk &o)const{ 17 return val>o.val; 18 } 19 }; 20 priority_queue<dijk>S; 21 bool vis[inf]; 22 void dijkstra(){ 23 memset(dis,0x3f,sizeof(dis)); 24 dis[s]=0; 25 S.push((dijk){s,0}); 26 while(!S.empty()){ 27 dijk u=S.top(); 28 S.pop(); 29 if(vis[u.id])continue; 30 vis[u.id]=1; 31 for(int i=fi[u.id];i;i=nxt[i]){ 32 if(dis[to[i]]>dis[u.id]+cost[i]){ 33 dis[to[i]]=dis[u.id]+cost[i]; 34 S.push((dijk){to[i],dis[to[i]]}); 35 } 36 } 37 } 38 } 39 int main() 40 { 41 scanf("%d%d",&n,&m); 42 for(int i=1;i<=m;i++){ 43 int x,y; 44 LL z; 45 scanf("%d%d%lld",&x,&y,&z); 46 link(x,y,z<<1);link(y,x,z<<1); 47 } 48 for(int i=1;i<=n;i++){ 49 LL z; 50 scanf("%lld",&z); 51 link(s,i,z); 52 } 53 dijkstra(); 54 for(int i=1;i<=n;i++)printf("%lld ",dis[i]); 55 puts(""); 56 return 0; 57 }
真的超级感谢这道题目啊,之前写的dijkstra一直是不对的,以至于我一直对其复杂度怀疑(事实上确实是不对的),甚至觉得他和不优化的dijkstra不像是一种算法了,普通的dijkstra每一个点只会被拿来更新一次,而我之前写的优化后的dijkstra是没有标记数组的,也就是说每一个点可能被访问多次,复杂度就不是nlog+m了。而且之前从来没有因为这个被卡过,这次体会到了。
原文地址:https://www.cnblogs.com/hyghb/p/8452797.html
时间: 2024-10-05 02:50:21