求终点卖书钱减去起点买书钱再减去车费的最大利润
单源最短路径问题(四种单源最短路径算法),将城市之间的路径权值转换为p[a]-p[b]-c(p[]城市价,c车费),用队列优化的spfa求解,自己手写队列,再加上超级源点和超级汇点寻找最长路径
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+5;
const int inf=1<<30;
int dist[N],cnt[N],queue[N]; //记录最短距离值,入队次数,手动队列
int head[N]; //单点的邻接表头指针
bool vis[N];
struct Edge{
int to;
int next;
int w;
}edge[5*N]; //邻接表
int len;
void addEdge(int u,int v,int sub){
edge[len].to=v;
edge[len].next=head[u];
edge[len].w=sub;
head[u]=len++;
}
bool spfa(int st,int n){
int front=0,rear=0;
for(int i=0;i<=n;i++){//初始化
if(i==st){
queue[rear++]=i;
vis[i]=true;
cnt[i]=1;
dist[i]=0;
}
else{
vis[i]=false;
cnt[i]=0;
dist[i]=-inf;
}
}
while(front!=rear){
int u=queue[front++];
vis[u]=false; //出队
if(front>=N)
front=0; //循环队列
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].to;
if(dist[v]<dist[u]+edge[i].w){
dist[v]=dist[u]+edge[i].w;
if(!vis[v]){
vis[v]=true;
queue[rear++]=v;
if(rear>=N)
rear=0; //循环队列
if(++cnt[v]>n)
return false; //负环
}
}
}
}
return true;
}
int main(){
int t,n,a,b,c;
int p[N]; //城市书价
scanf("%d",&t);
while(t--){
len=0;
memset(head,-1,sizeof(head));
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&p[i]);
for(int i=1;i<n;i++){
scanf("%d %d %d",&a,&b,&c);
addEdge(a,b,p[b]-p[a]-c);
addEdge(b,a,p[a]-p[b]-c);
}
for(int i=1;i<=n;i++){
addEdge(0,i,0); //超级源点
addEdge(i,n+1,0); //超级汇点
}
spfa(0,n+1);
printf("%d\n",dist[n+1]);
}
return 0;
}