P1629 邮递员送信
题目描述
有一个邮递员要送东西,邮局在节点1.他总共要送N-1样东西,其目的地分别是2~N。由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有M条道路,通过每条道路需要一定的时间。这个邮递员每次只能带一样东西。求送完这N-1样东西并且最终回到邮局最少需要多少时间。
输入输出格式
输入格式:
第一行包括两个整数N和M。
第2到第M+1行,每行三个数字U、V、W,表示从A到B有一条需要W时间的道路。 满足1<=U,V<=N,1<=W<=10000,输入保证任意两点都能互相到达。
【数据规模】
对于30%的数据,有1≤N≤200;
对于100%的数据,有1≤N≤1000,1≤M≤100000。
输出格式:
输出仅一行,包含一个整数,为最少需要的时间。
输入输出样例
我们看到这个题首先想到的就是Floyd,因为这是有向边,而且邮递员出去之后还要再回来的嘛。
but应该只能拿一部分分,因为范围太大Ο(n^3)跑不动,
那么就另寻他路喽。
(绞尽脑汁终于想了出来)
建两张图,跑两遍dijkstra就能过了,至于为什么,看下面
我们先正常的建图,这个跑出来是到每一个节点的距离然后把这些距离加起来,存到ANS里面,然后反向建一张图,为啥呢?
因为我们反向建一张图再跑的时候从别的点回到起点的边就变成了从起点到别的点,这是我们跑出来的结果就是从每一个节点再回到起点的距离,把这些距离也加到ANS中,到最后输出ANS就可以了
啦啦啦啦啦啦啦 上代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define MAXN 100005
#define INF 2147483647
using namespace std;
int n, m, cnt;
long long ans;
int u[MAXN], v[MAXN], w[MAXN];
int first[MAXN], next[MAXN];
bool book[MAXN];
int ddd[1005][1005];
int dis[1005];
int uu[MAXN], vv[MAXN], ww[MAXN];
int f[MAXN], nn[MAXN];
int main() {
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++) {
dis[i] = INF;
}
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
ddd[i][j] = INF;
dis[1] = 0;
memset(f, -1, sizeof(f));
memset(first, -1, sizeof(first));
for(int i=1; i<=m; i++) {
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
ddd[x][y] = min(ddd[x][y], z);
}
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
if(ddd[i][j] != INF) {
cnt++;
u[cnt] = i, v[cnt] = j, w[cnt] = ddd[i][j];
next[cnt] = first[u[cnt]];
first[u[cnt]] = cnt;
uu[cnt] = j, vv[cnt] = i, ww[cnt] = ddd[i][j];
nn[cnt] = f[uu[cnt]];
f[uu[cnt]] = cnt;
}
}
}
for(int i=1; i<n; i++) {
int minn = INF, x;
for(int j=1; j<=n; j++) {
if(minn > dis[j]&&book[j] == 0) {
minn = dis[j];
x = j;
}
}
book[x] = 1;
int k = first[x];
while(k != -1) {
if(dis[v[k]] > dis[u[k]]+w[k]) {
dis[v[k]] = dis[u[k]]+w[k];
}
k = next[k];
}
}
for(int i=2; i<=n; i++) {
// if(dis[i] != INF)
ans += dis[i];
}
for(int i=1; i<=n; i++) {
dis[i] = INF;
}
dis[1] = 0;
memset(book, 0, sizeof(book));
for(int i=1; i<n; i++) {
int minn = INF, h;
for(int j=1; j<=n; j++) {
if(minn > dis[j]&&book[j] == 0) {
minn = dis[j];
h = j;
}
}
book[h] = 1;
int k = f[h];
while(k != -1) {
if(dis[vv[k]] > dis[uu[k]]+ww[k]) {
dis[vv[k]] = dis[uu[k]]+ww[k];
}
k = nn[k];
}
}
for(int i=2; i<=n; i++) {
// if(dis[i] != INF)
ans += dis[i];
}
printf("%lld\n",ans);
}