POJ 2060 (最小路徑覆蓋)
阿新 • • 發佈:2019-02-20
題意:在二維的平面中,給出一些任務,每個任務要求在指定的時間,必須有一輛taxi從起點出發,並最終到達終點,由於可能產生時間衝突(具體參詳題目),所以可能需要多輛taxi,問需要最少的taxi數量是多少。
構圖:可以將每個任務看成一個點,如果兩個任務的時間沒有衝突,則從時間較早的任務點向時間較晚的任務點連線一條有向邊,顯然,這幅圖的任意一條路徑上的任務都可以由一輛taxi來完成,題目所求變成找出最少的路徑數量,使得這些路徑能覆蓋圖上的所有節點。
到此,題目變成了求最小路徑覆蓋問題,最小路徑覆蓋數 = 總節點數 – 最大獨立集數(最大匹配數),這是被證明了的公式,因此可以將原圖拆點,構成二分圖(起點在左圖,終點在右圖),求最大匹配數即可。在網上看到了一個重要的小細節,直接連結
// 188 Ms #include <iostream> #include <cstring> #include <cstdio> #include <vector> #include <cstdlib> #define N 510 using namespace std; struct Data { int begin, end; int x1, y1, x2, y2; }o[N]; vector<int> G1[N]; int match[N]; bool mark[N]; int DFS(int n, int cur) { for (int i = 0; i < G1[cur].size(); i++) { int u = G1[cur][i]; if (mark[u]) continue; mark[u] = 1; if (!match[u] || DFS(n, match[u])) { match[u] = cur; return 1; } } return 0; } int main() { int Case, n; scanf("%d", &Case); while (Case--) { memset(G1, 0, sizeof(G1)); memset(match, 0, sizeof(match)); scanf("%d", &n); int a, b; for (int i = 1; i <= n; i++) { scanf("%d:%d %d %d %d %d", &a, &b, &o[i].x1, &o[i].y1, &o[i].x2, &o[i].y2); o[i].begin = a * 60 + b; o[i].end = o[i].begin + abs(o[i].x1-o[i].x2) + abs(o[i].y1-o[i].y2); } for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { int dis = abs(o[i].x2 - o[j].x1) + abs(o[i].y2 - o[j].y1); if (o[i].end + dis < o[j].begin) G1[i].push_back(j); } } // 構圖 int cnt = 0; for (int i = 1; i <= n; i++) { memset(mark, 0, sizeof(mark)); cnt += DFS(n, i); } // 計算最大二分匹配 printf("%d\n", n - cnt); } return 0; }