Repairing Company(poj 3216)

题目大意:

有Q个地点,告诉你Q个地点之间的相互距离(从i地点赶到j地点需要的时间)。有M项任务,

给你M项任务所在的地点block、开始时间start和任务完成需要时间time。一个工人只有在

他准备完成的下一项任务开始之前完成手上的任务,然后在下一项任务开始之前赶到下一项

任务的地点,才能完成这两项任务。问:最少需要多少个工人来完成这M项任务。

/*
  对于这类二分图的最小路径覆盖,我是这么理解的:
  那这道题来说,我们可以先假设一共需要m个工人,然后经过二分图匹配,
  每匹配一对,说明有两项任务可以由一个工人完成,m就减1,最后,剩下
  的m即为所求
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#define M 210
#define N 22
using namespace std;
int map[N][N],used[M],belong[M],a[M][M],q,m;
struct node
{
    int pos,begin,end;
};node e[M];
void Floyed()
{
    for(int k=1;k<=q;k++)
      for(int i=1;i<=q;i++)
        for(int j=1;j<=q;j++)
          if(i!=j&&i!=k&&j!=k)
            map[i][j]=min(map[i][k]+map[k][j],map[i][j]);
}
int find(int i)
{
    for(int j=1;j<=m;j++)
      if(!used[j]&&a[i][j])
      {
          used[j]=1;
          if(!belong[j]||find(belong[j]))
          {
              belong[j]=i;
              return 1;
          }
      }
    return 0;
}
int main()
{
    while(1)
    {
        memset(map,0x3f3f3f3f,sizeof(map));
        memset(used,0,sizeof(used));
        memset(belong,0,sizeof(belong));
        memset(a,0,sizeof(a));
        scanf("%d%d",&q,&m);
        if(q==0&&m==0)break;
        for(int i=1;i<=q;i++)
          for(int j=1;j<=q;j++)
          {
              int x;
              scanf("%d",&x);
              if(x!=-1)
              map[i][j]=map[j][i]=x;
          }
        Floyed();
        for(int i=1;i<=m;i++)
        {
            int x;
            scanf("%d%d%d",&e[i].pos,&e[i].begin,&x);
            e[i].end=e[i].begin+x;
        }
          
        for(int i=1;i<=m;i++)
          for(int j=1;j<=m;j++)
            if(i!=j&&e[j].begin-e[i].end>=map[e[i].pos][e[j].pos])
              a[i][j]=1;
        int tot=0;
        for(int i=1;i<=m;i++)
          if(find(i))
          {
              memset(used,0,sizeof(used));
              tot++;
          }
        printf("%d\n",m-tot);
    }
    return 0;
}
View Code

 

posted @ 2016-07-01 18:12  karles~  阅读(169)  评论(0编辑  收藏  举报