题目在 :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 10000000 struct 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; }