## [$AcWing$ $1127$ 香甜的黄油](https://www.acwing.com/solution/content/11172/) ### 一、题目描述 农夫$John$发现了做出全威斯康辛州最甜的黄油的方法:**糖**。 把糖放在一片牧场上,他知道 $N$ 只奶牛会过来舔它,这样就能做出能卖好价钱的超甜黄油。 当然,他将付出额外的费用在奶牛上。 农夫$John$很狡猾,就像以前的巴甫洛夫,他知道他可以训练这些奶牛,让它们在听到铃声时去一个特定的牧场。 他打算将糖放在那里然后下午发出铃声,以至他可以在晚上挤奶。 农夫$John$知道每只奶牛都在各自喜欢的牧场(一个牧场不一定只有一头牛)。 给出各头牛在的牧场和牧场间的路线,找出使 **所有牛到达的路程和最短的牧场**(他将把糖放在那)。 数据保证至少存在一个牧场和所有牛所在的牧场连通。 **输入格式** 第一行: 三个数:奶牛数 $N$,牧场数 $P$,牧场间道路数 $C$。 第二行到第 $N+1$ 行: $1$ 到 $N$ 头奶牛所在的牧场号。 第 $N+2$ 行到第 $N+C+1$ 行:每行有三个数:相连的牧场$A、B$,两牧场间距 $D$,当然,连接是双向的。 **输出格式** 共一行,输出奶牛必须行走的最小的距离和。 ### 二、算法分析 **枚举所有点作为特定牧场,求特定牧场到所有点的最短距离** 点的个数$n= 800$,边的个数$m=1500$ 堆优化版$dijkstra$ 复杂度是$O(n\times m \times log_2n)$ = $n \times m \times log_2n \approx 800 \times 1500 \times 10 = 1.2∗10^7$ ### 三、$Dijkstra$ ```cpp {.line-numbers} #include using namespace std; typedef pair PII; const int N = 810; // 牧场数 上限800 const int M = 3000; // 牧场间道路数 上限1450,无向图开双倍 const int INF = 0x3f3f3f3f; // 邻接表 int h[N], e[M], w[M], ne[M], idx; void add(int a, int b, int c) { e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++; } int n, p, m; // 三个数:奶牛数 ,牧场数 ,牧场间道路数 int id[N]; // 每只奶牛在哪个牧场 int dis[N]; // 记录起点到任意点的最短路径 bool st[N]; // 标识每个牧场是否入过队列 int dijkstra(int S) { memset(st, 0, sizeof st); memset(dis, 0x3f, sizeof dis); dis[S] = 0; priority_queue, greater> q; q.push({0, S}); while (q.size()) { PII t = q.top(); q.pop(); int u = t.second; if (st[u]) continue; st[u] = true; for (int i = h[u]; ~i; i = ne[i]) { int v = e[i]; if (dis[v] > dis[u] + w[i]) { dis[v] = dis[u] + w[i]; q.push({dis[v], v}); } } } int res = 0; for (int i = 1; i <= n; i++) { // 遍历每只奶牛 int j = id[i]; // j号牧场 if (dis[j] == INF) return INF; // 如果j号牧场失联了,则无法获得结果 res += dis[j]; // 累加一个最小距离 } return res; // 整体的最小距离 } int main() { memset(h, -1, sizeof h); cin >> n >> p >> m; // 奶牛数,牧场数,牧场间道路数 for (int i = 1; i <= n; i++) cin >> id[i]; // 1 到 N 头奶牛所在的牧场号 while (m--) { int a, b, c; cin >> a >> b >> c; add(a, b, c), add(b, a, c); } int ans = INF; // 枚举每个牧场为出发点,计算它的最短距离和 中的最小值 for (int i = 1; i <= p; i++) ans = min(ans, dijkstra(i)); printf("%d\n", ans); return 0; } ```