题目链接:
http://poj.org/problem?id=3216
题目大意:
有Q个地点,告诉你Q个地点之间的相互距离(从i地点赶到j地点需要的时间)。有M项任务,
给你M项任务所在的地点block、开始时间start和任务完成需要时间time。一个工人只有在
他准备完成的下一项任务开始之前完成手上的任务,然后在下一项任务开始之前赶到下一项
任务的地点,才能完成这两项任务。问:最少需要多少个工人来完成这M项任务。
思路:
先用Floyd算出Q个地点之间相互最短距离。然后建立一个二分图,每边都是M项任务,如果
能在任务j完成之前将i任务完成并能赶到任务j的地点,就建立一条边。那么问题就变为了求
二分图最小路径覆盖问题。而二分图最小路径覆盖 = 点数 - 二分图最大匹配。二分图最大匹
配用匈牙利算法来求。
AC代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> using namespace std; const int MAXN = 25; const int MAXM = 220; const int INF = 0xffffff0; int G[MAXN][MAXN],Dist[MAXN][MAXN]; struct Node { int block; int start; int time; }node[MAXM]; void Floyd(int N) { for(int i = 1; i <= N; ++i) for(int j = 1; j <= N; ++j) Dist[i][j] = G[i][j]; for(int k = 1; k <= N; ++k) for(int i = 1; i <= N; ++i) for(int j = 1; j <= N; ++j) if(Dist[i][k] + Dist[k][j] < Dist[i][j]) //加Dist[i][j] != INF && Dist[k][j] != INF出错。。。 Dist[i][j] = Dist[i][k] + Dist[k][j]; } bool Map[MAXM][MAXM],Mask[MAXM]; int NX,NY; int cx[MAXM],cy[MAXM]; int FindPath(int u) { for(int i = 1; i <= NY; ++i) { if(Map[u][i] && !Mask[i]) { Mask[i] = 1; if(cy[i] == -1 || FindPath(cy[i])) { cy[i] = u; cx[u] = i; return 1; } } } return 0; } int MaxMatch() { for(int i = 1; i <= NX; ++i) cx[i] = -1; for(int i = 1; i <= NY; ++i) cy[i] = -1; int res = 0; for(int i = 1; i <= NX; ++i) { if(cx[i] == -1) { for(int j = 1; j <= NY; ++j) Mask[j] = 0; res += FindPath(i); } } return res; } int main() { int Q,M; while(~scanf("%d%d",&Q,&M) && (Q||M)) { for(int i = 1; i <= Q; ++i) { for(int j = 1; j <= Q; ++j) { scanf("%d",&G[i][j]); if(G[i][j] == -1) G[i][j] = INF; } } for(int i = 1; i <= M; ++i) scanf("%d%d%d",&node[i].block,&node[i].start,&node[i].time); Floyd(Q); memset(Map,0,sizeof(Map)); for(int i = 1; i <= M; ++i) { for(int j = 1; j <= M; ++j) { int u = node[i].block; int v = node[j].block; if(i != j && Dist[u][v] != INF) { if(node[i].start + node[i].time + Dist[u][v] <= node[j].start) Map[i][j] = 1; } } } NX = NY = M; printf("%d\n",M-MaxMatch()); } return 0; }
时间: 2024-10-10 20:22:48