POJ 3216 Repairing Company【二分图最小路径覆盖】
题意: 告诉你 Q 格街区,一共有 M d 个任务分布在这Q 个街区里面,知道了每个任务的开始时间和需要一个人的完成时间,
问最少需要派多少人才能做完所有的任务。
分析: 求二分图的最小路径覆盖,分两种情况
① 两个第 I 个任务和 第 J g个任务在同一街区,如果满足 t[i]+d[i]<=t[j] 那么两个任务构成一个匹配,
即第I 个任务和 第J 个任务可由同一个人先后完成,
②两个任务在不同街区,如果满足 t[i]+d[i]+dis[i][j]<=t[j],那么两任务亦构成一个匹配。
求出最大匹配,最小路径覆盖即为m - 最大匹配
其中每个点之间的最短路径可以通过floyd求得
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<stdio.h> #include<string.h> #define clr(x)memset(x,0,sizeof(x)) struct node { int to,next; }q[100000]; struct pe { int bl,s,d; }p[202]; int head[202]; int tot; int link[202]; int v[202]; void add(int s,int u) { q[tot].to=u; q[tot].next=head[s]; head[s]=tot++; } int find(int x) { int i,k; for(i=head[x];i;i=q[i].next) { k=q[i].to; if(!v[k]) { v[k]=1; if(link[k]==0||find(link[k])) { link[k]=x; return 1; } } } return 0; } int g[22][22]; int main() { int sum,i,j,k,Q,m,a,b,c; while(scanf("%d%d",&Q,&m),Q&&m) { for(i=1;i<=Q;i++) for(j=1;j<=Q;j++) scanf("%d",&g[i][j]); for(k=1;k<=Q;k++) for(i=1;i<=Q;i++) { if(g[i][k]!=-1) for(j=1;j<=Q;j++) if(g[k][j]!=-1&&(g[i][k]+g[k][j]<g[i][j]||g[i][j]==-1)) g[i][j]=g[i][k]+g[k][j]; } for(i=1;i<=m;i++) scanf("%d%d%d",&p[i].bl,&p[i].s,&p[i].d); clr(link); clr(head); tot=1; for(i=1;i<=m;i++) for(j=1;j<=m;j++) if(i!=j) { if(p[i].d+p[i].s+g[p[i].bl][p[j].bl]<=p[j].s) add(i,j); } sum=0; for(i=1;i<=m;i++) { clr(v); if(find(i)) sum++; } printf("%d\n",m-sum); } return 0; }