题意:有一个起始站点,从这里送n个学生去其余的n-1个站点邀请人们去CSS,然后再返回CSS,使得总的花费最小。注意每次只能送一个,返回时每次也只能送一个,而且每条路是单向的。
分析:这相当于一个有向图,我们只需两次调用SPFA算法即可,第一次求出初始站点(在这里是1)到其它所有站点的最小花费,然后相加;第二次将图反向建立,即所有的边反向,再求出初始站点(这里是1)到其它站点的最小费用,之后相加,第二步的图反向后按照第一次的求法就相当于从其它所有点到初始点的最小距离,因为算法只能求单点到多点而不能求多点到单点。最后把两次的结果相加即可得到最终结果。
#include<iostream> #include<vector> #include<queue> using namespace std; int u[1000001]; int v[1000001]; int w[1000001]; bool vis[1000001]; int d[1000001]; int first[1000001]; int Next[1000001]; void InitAndInput(int n,int m) //输入图 { int i; for(i=1;i<=n;i++) first[i]=-1; for(i=0;i<m;i++) Next[i]=-1; for(i=0;i<m;i++) { cin>>u[i]>>v[i]>>w[i]; Next[i]=first[u[i]]; first[u[i]]=i; } } void InverseBulid(int n,int m) //反向建立图 { int i; for(i=1;i<=n;i++) first[i]=-1; for(i=0;i<m;i++) Next[i]=-1; for(i=0;i<m;i++) { Next[i]=first[v[i]]; first[v[i]]=i; } } void spfa(int n,int s,bool flag) //flag表示当前处理的是反向建立后的图还是一开始的图,false反向,true开始 { queue<int> q; int i,x,y; for(i=1;i<=n;i++) vis[i]=false; for(i=1;i<=n;i++) d[i]=(i==s)?0:0x7fffffff; //初始化,自己到自己为0,其他到自己相当于无穷大 q.push(s); while(!q.empty()) { x=q.front(); q.pop(); vis[x]=false; for(i=first[x];i!=-1;i=Next[i]) { y=flag?v[i]:u[i]; if(d[y]>d[x]+w[i]) { d[y]=d[x]+w[i]; if(!vis[y]) { vis[y]=true; q.push(y); } } } } } int main() { int P,Q,N,sum,i; cin>>N; while(N--) { sum=0; cin>>P>>Q; InitAndInput(P,Q); spfa(P,1,true); //正向求出最小和 for(i=2;i<=P;i++) sum+=d[i]; InverseBulid(P,Q); //反向建图 spfa(P,1,false); //反向求出最小和 for(i=2;i<=P;i++) sum+=d[i]; cout<<sum<<endl; } return 0; }
时间: 2024-10-27 00:03:13