题目的意思是有N个车站,N个人,将N个人从一个车站分配到N个车站去,再让他们回到这个车站。交通系统全部是单项的。求总花费最小。
一开始想到FLoyd,但看了数据范围,发现做不了,后来想到做两遍Dijkstra
思路是,求一遍某个点出发的单源最短路,再将图反向,再求一边这个点的单源最短路。两遍的结果保存到两个数组,最后将两个数组中的所有值全部相加然后输出。
原理是第一遍求得从一个点出发到其他所有点的最短路径也就是最小花费,将图反转之后再求一遍,求出的是从所有其他点到这个点的最短路,(最新小花费)。
下面代码在服务器上能过,但在自己电脑上测试时需要将long long 改为int,或者缩小MaxN的值,因为本机申请不到这么大的数组。
#include <iostream>
#include <memory.h>
#include <vector>
#include <queue>
#include <stdio.h>
#define MaxN 1000005
#define INF 1000000
struct node
{
int e,w;
node(int ee,int ww):e(ee),w(ww) {}
node(){}
bool friend operator<(node n1,node n2)
{
return n1.w>n2.w;
}
};
using namespace std;
int N,M;
void Dijistra(vector<vector<node> > v,long long dist[MaxN])
{
for(int i=1;i<=N;i++)
dist[i]=INF;
dist[1]=0;
priority_queue<node> Q;
Q.push(node(1,0));
while(!Q.empty())
{
node now=Q.top();
Q.pop();
int S=now.e;
for(int i=0;i<v[S].size();i++)
{
int E=v[S][i].e;
if(dist[S]+v[S][i].w<dist[E])
{
dist[E]=dist[S]+v[S][i].w;
Q.push(node(E,dist[E]));
}
}
}
}
void output(long long dist1[MaxN],long long dist2[MaxN])
{
long long ans=0;
for(int i=1;i<=N;i++)
ans+=(dist1[i]+dist2[i]);
cout<<ans<<endl;
}
int main()
{
vector<vector<node> > v1;
vector<vector<node> > v2;
long long dist1[MaxN],dist2[MaxN];
int a,b,c;
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&N,&M);
v1.clear();v1.resize(N+1);
v2.clear();v2.resize(N+1);
while(M--)
{
scanf("%d%d%d",&a,&b,&c);
v1[a].push_back(node(b,c));
v2[b].push_back(node(a,c));
}
Dijistra(v1,dist1);
Dijistra(v2,dist2);
output(dist1,dist2);
}
return 0;
}