題目在 :http://poj.org/problem?id=3216
題目的大意說,我們的維修隊,負責N個街區的維修任務。現在知道各個街區直接的距離。
現在有M個任務,每個任務有各自所在的街區(任務可以出現在同一個街區),任務最遲的開始時間,任務期間資訊。
現在編程求出,最少可以派出幾名維修員完成維修任務。
在這裡我想自己把做題出現的兩類可以用最大二分圖匹配的總結一下。
第一類問題是赤裸的二分匹配,說白了就是圖中有多少個點,然後給出點的串連關係,然後根據這些關係來求,最大匹配或者最小點覆蓋,或者最小路徑覆蓋
例如:
http://poj.org/problem?id=1466 直接根據“羅曼史”來建模,求出最大獨立子集
http://poj.org/problem?id=3692 根據男孩和女孩的不認識關係來建立二分圖,求出最小點覆蓋
第二類問題是, 雖然表面給出一個圖,但是圖中一些節點是特殊的,我們的任務不是針對這個圖來求解,而是針對這些特殊的點,重建立立新的圖G,然後在把G轉換成二分圖求最大路徑覆蓋等問題。
例如:
http://poj.org/problem?id=3020 天線覆蓋問題是針對
圖中的每個 必須覆蓋的訊號點
http://poj.org/problem?id=2594 可達性的定義是根據探寶規則定義的,即可以通過重複點
http://poj.org/problem?id=1422 根據行和列的鄰接關係建立二分圖,然後求出最小點覆蓋。
http://poj.org/problem?id=1548 根據有垃圾的點來建立二分圖,然後求出最小路徑覆蓋
http://poj.org/problem?id=3041 根據行列來建立二分圖,然後求出最小點覆蓋
http://poj.org/problem?id=1325 根據兩台機器的不同模式,來建模,然後求最小點覆蓋。
在第二類問題的時候,有時候,根據問題(例如1548 撿到所有的垃圾 ) 建立新圖G的時候,可達是需要自己來求的。這個過程很多時候就要輔助一些其他的演算法了,例如在2594利用floyd演算法來求出所有點之間的可達情況。例如在1548中,例如垃圾點的位置是否符合機器人遍曆的方向來判定。
其實我們這個題目也是屬於第二個類型的,不同的任務是否有可達,就是說當前任務 i 在最晚的時刻 + i的期間 +從i到j所在block的時間 < j 最遲開始時間。
所以程式如下:
#include <stdio.h>#include <memory.h>#include <algorithm>using namespace std;#define MAX_NUM 22#define MAX_TASK 201#define MAX_DISTANCE 10000000struct Task{int block;int deadLine;int durationTime;};Task vTasks[MAX_TASK];int vvAdj[MAX_NUM][MAX_NUM];int visit[MAX_TASK];int vvTask[MAX_TASK][MAX_TASK];int matched[MAX_TASK];int nTask, nPoins;void floyd(){int k,i,j;for( k = 0; k < nPoins; k++){for( i = 0; i < nPoins; i++){for( j = 0; j < nPoins; j++){if( i != j){vvAdj[i][j] = min(vvAdj[i][j], vvAdj[i][k] + vvAdj[k][j]);}}}}}bool dfs(int f){for( int i = 0; i < nTask; i++){if(!visit[i] && vvTask[f][i]){visit[i] = true;if(matched[i] == -1 || dfs(matched[i])){matched[i] = f;return true;}}}return false;}bool TaskReachable(int i, int j){return (vTasks[i].deadLine + vTasks[i].durationTime + vvAdj[vTasks[i].block][vTasks[j].block]) <= vTasks[j].deadLine;}void CreateTaskGraph(){int i,j;for( i = 0; i < nTask; i++){for( j = 0; j < nTask; j++){if( i != j && TaskReachable(i, j)){vvTask[i][j] = 1;}}}}int main(){int i,j;int dis;while(scanf("%d%d", &nPoins, &nTask)){if(nPoins == 0 && nTask == 0){break;}memset(vvAdj, 0, sizeof(vvAdj));memset(vvTask, 0, sizeof(vvTask));memset(matched, -1, sizeof(matched));for( i = 0; i < nPoins; i++ ){for( j = 0; j < nPoins; j ++){scanf("%d", &dis);if(dis == -1){vvAdj[i][j] = MAX_DISTANCE;}else{vvAdj[i][j] = dis;}}}int tt, dt, block;for( i = 0; i < nTask; i++){scanf("%d%d%d", &block, &tt, &dt);vTasks[i].deadLine = tt;vTasks[i].durationTime = dt;vTasks[i].block = block - 1;}floyd();CreateTaskGraph();int count = 0;for( i = 0; i < nTask; i++){memset(visit, 0, sizeof(visit));if(dfs(i)){count++;}}printf("%d\n", nTask - count);}return 0;}