【代碼超詳解】HDU 4370 0 or 1(思維 · 數形結合 + Dijkstra 單源最短路 · 單源最小環)

傳送門

一、題目描述

在這裏插入圖片描述

二、算法分析說明與代碼編寫指導

矩陣 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));
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章