原题链接:vjudge传送门
题目大意:
求1号点到各个点的最短距离,以及各个点到1号点的最短距离,相加即可。题目保证是连通图
具体思路:
图中所有点到指定点的最短距离可以转化为求指定点到所有点的最短距离
因此用正反向存图+2次Dijkstra,数据量很大,用堆优化
随便说点:
做这道题我真的体会到链式前向星的好处,
一开始用vector前向星存图+dijkstra+优先队列(堆优化) TLE
紧接着用vector前向星存图+spfa TLE
最后很无奈查了一下链式前向星存图+dijkstra+优先队列才ac
具体代码:
//链式前向星存图+dijkstra+优先队列
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const int N = 1000005, M = 1000005*2;
const LL INF = 0x3f3f3f3f3f3f3f3f;
struct Node {
int to, next;
LL w;
}edg[M];
int c, n, m, len, choice;
LL d[N],rd[N];
int head[N], rhead[N];
int visit[N];
void add(int h[], int u, int v, LL w) {
edg[len].w = w;
edg[len].to = v;
edg[len].next = h[u];
h[u] = len++;
}
struct cmp {
bool operator()(int a, int b)
{
if(choice==1) //代表正向dij的比较
return d[a] > d[b]; //这比较函数,涨见识,可以用到全局变量
return rd[a] > rd[b];
}
};
LL dijkstra(LL d[], int head[])
{
memset(visit, 0, sizeof(visit));
priority_queue<int, vector<int>, cmp> q;
d[1] = 0;
q.push(1); //一开始1号入队,然后通过1号把,其它非无穷的点入队
while (q.size())
{
int t = q.top();
q.pop();
if (visit[t])continue; //避免重复更新,也可以在下方push前判断,避免重复入队进行更新
visit[t] = 1;
for (int i = head[t]; i; i = edg[i].next)
{
int v = edg[i].to;
LL w = d[t] + edg[i].w;
if (d[v] > w) {
d[v] = w;
q.push(v);//被更新,入队列参与最小堆操作
}
}
}
LL sum = 0;
for (int i = 1; i <= n; i++)
sum += d[i];
return sum;
}
int main()
{
scanf("%d", &c);
while (c--)
{
len = 1;
scanf("%d%d", &n, &m);
memset(head, 0, sizeof(head));
memset(rhead, 0, sizeof(rhead));
for (int i = 1; i <= m; i++)
{
int s, d;
LL p;
scanf("%d%d%lld", &s, &d, &p);
add(head, s, d, p);
add(rhead, d, s, p);
}
memset(d, 0x3f, sizeof(d));
memset(rd, 0x3f, sizeof(rd));
choice = 1;
LL sum = dijkstra(d, head);
choice = 0;
sum += dijkstra(rd, rhead);
printf("%lld\n", sum);
}
return 0;
}
分割线
最后不才的附上TLE的代码
//dijkstra
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const int N = 1000005;
const LL INF = 0x3f3f3f3f3f3f3f3f;
struct Node {
int to;
LL w;
Node(int d, LL p) {
to = d, w = p; }
};
//vector maps[N];
//vector rmaps[N];
int c, n, m;
LL d[N];
int visit[N];
struct cmp {
bool operator()(int a, int b)
{
return d[a] > d[b]; //这比较函数,涨见识,可以用到全局变量
}
};
LL dijkstra(vector<vector<Node> > maps)
{
memset(visit, 0, sizeof(visit));
for (vector<Node>::iterator it = maps[1].begin(); it != maps[1].end(); it++)
d[it->to] = it->w;
d[1] = 0;
priority_queue<int, vector<int>,cmp> q;
q.push(1); //一开始1号入队,然后通过1号把,其它非无穷的点入队
while (q.size())
{
int t = q.top();
q.pop();
visit[t] = 1;
for (vector<Node>::iterator it = maps[t].begin(); it!= maps[t].end(); it++)
{
if (!visit[it->to])
{
d[it->to] = min(d[it->to], d[t] + it->w);
q.push(it->to); //被更新,入队列参与最小堆操作
}
}
}
LL sum= 0;
for (int i = 1; i <= n; i++)
sum += d[i];
return sum;
}
int main()
{
scanf("%d", &c);
while (c--)
{
scanf("%d%d", &n, &m);
vector<vector<Node> > maps(n+1); //stl前向星存图
vector<vector<Node> > rmaps(n+1); //stl前向星存图
memset(d, 0x3f, sizeof(d));
for (int i = 1; i <= m; i++)
{
int s, d;
LL p;
scanf("%d%d%lld", &s, &d, &p);
maps[s].push_back(Node(d, p));
rmaps[d].push_back(Node(s, p));
}
LL sum = dijkstra(maps);
memset(d, 0x3f, sizeof(d));
sum+=dijkstra(rmaps);
printf("%lld\n", sum);
}
return 0;
}
//spfa
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const int N = 1000005;
const LL INF = 0x3f3f3f3f3f3f3f3f;
struct Node {
int to;
LL w;
Node(int d, LL p) {
to = d, w = p; }
};
//vector maps[N];
//vector rmaps[N];
int c, n, m;
LL d[N];
int visit[N];
struct cmp {
bool operator()(int a, int b)
{
return d[a] > d[b];
}
};
LL spfa(vector<vector<Node> > maps)
{
memset(visit, 0, sizeof(visit));
queue<int> q;
q.push(1);
d[1] = 0;
visit[1] = 1;
while (q.size())
{
int t = q.front();
q.pop();
visit[t] = 0;
for (vector<Node>::iterator it = maps[t].begin(); it!= maps[t].end(); it++)
{
if (d[it->to] > d[t] + it->w) {
d[it->to] = d[t] + it->w;
if (!visit[it->to]) {
q.push(it->to);
visit[it->to] = 1;
}
}
}
}
LL sum= 0;
for (int i = 1; i <= n; i++)
sum += d[i];
return sum;
}
int main()
{
scanf("%d", &c);
while (c--)
{
scanf("%d%d", &n, &m);
vector<vector<Node> > maps(n+1); //stl前向星存图
vector<vector<Node> > rmaps(n+1); //stl前向星存图
memset(d, 0x3f, sizeof(d));
for (int i = 1; i <= m; i++)
{
int s, d;
LL p;
scanf("%d%d%lld", &s, &d, &p);
maps[s].push_back(Node(d, p));
rmaps[d].push_back(Node(s, p));
}
LL sum = spfa(maps);
memset(d, 0x3f, sizeof(d));
sum+= spfa(rmaps);
printf("%lld\n", sum);
}
return 0;
}