一、題目描述
二、算法分析說明與代碼編寫指導
矩陣 X 的每一項只取 0 或 1。如果能聯想到無重邊的圖的鄰接矩陣,就好處理多了。
三個條件對應的對圖的約束:
1、1 節點的出度爲 1。
2、n 節點的入度爲 1。
3、2 ~ n - 1 節點的入度必須等於出度。
滿足如上三個條件的是一條 1 到 n 的簡單路徑,或者從 1 到 1 或從 n 到 n 的環。1 和 n 的自環要排除,因爲它們分別不滿足條件 1 和 2。
要求矩陣 C 和矩陣 X 每一項對應相乘的積之和最小,對應一條 1 到 n 的簡單路徑最短,所以要跑一次 1 到 n 的最短路。求從 1 到 n 的單源最短路時可以一同求得 1 到 1 的最小環。因爲還要求 n 到 n 的最小環,所以要以 n 爲源點再跑一次單源最短路,然後取最小的結果作爲答案即可。注意 1 到 1 的最小環和 n 到 n 的最小環的長度之和才符合 ∑(Cij * Xij) 的結果,而且在本題中要排除自環。
三、AC 代碼
#include<cstdio>
#include<algorithm>
#include<vector>
#include<bitset>
#include<queue>
#pragma warning(disable:4996)
using namespace std;
const unsigned dmax = 1 << 30, nmax = 301;
unsigned C[nmax][nmax], n, N, d[nmax], l, x, y, a, al; bitset<nmax> v;
inline void dijkstra(const unsigned& s) {
fill(d, d + n + 1, dmax); v.reset(); d[s] = 0; N = 0; l = dmax;
while (N != n) {
x = 0; for (unsigned i = 1; i <= n; ++i) { if (v[i] == false && d[i] < d[x])x = i; }
for (y = 1; y <= n; ++y) {
if (d[y] > d[x] + C[x][y]) { d[y] = d[x] + C[x][y]; }
}
if (x != s)l = min(l, d[x] + C[x][s]);
v[x] = true; ++N;
}
}
int main() {
for (;;) {
if (scanf("%u", &n) == EOF)return 0;
for (unsigned i = 1; i <= n; ++i) { fill(C[i] + 1, C[i] + n + 1, dmax); }
for (unsigned i = 1; i <= n; ++i)
for (unsigned j = 1; j <= n; ++j)scanf("%u", &C[i][j]);
dijkstra(1); a = d[n]; al = l;
dijkstra(n); al += l;
printf("%u\n", min(a, al));
}
}