poj 3216 Repairing Company(最短路Floyd + 最小路径覆盖 + 构图)

http://poj.org/problem?id=3216

Repairing Company
Time Limit: 1000MS   Memory Limit: 131072K
Total Submissions: 6776   Accepted: 1822

Description

Lily runs a repairing company that services the Q blocks in the city. One day the company receives M repair tasks, the ith of which occurs in block pi, has a deadline ti on any repairman’s arrival, which is also its starting time, and takes a single repairman di time to finish. Repairmen work alone on all tasks and must finish one task before moving on to another. With a map of the city in hand, Lily want to know the minimum number of repairmen that have to be assign to this day’s tasks.

Input

The input contains multiple test cases. Each test case begins with a line containing Q and M (0 < Q ≤ 20, 0 < M ≤ 200). Then follow Q lines each with Q integers, which represent a Q × Q matrix Δ = {δij}, where δij means a bidirectional road connects the ith and the jth blocks and requires δij time to go from one end to another. If δij = −1, such a road does not exist. The matrix is symmetric and all its diagonal elements are zeroes. Right below the matrix are M lines describing the repairing tasks. The ith of these lines contains piti and di. Two zeroes on a separate line come after the last test case.

Output

For each test case output one line containing the minimum number of repairmen that have to be assigned.

Sample Input

1 2
0
1 1 10
1 5 10
0 0

Sample Output

2

题目大意:Lily管理q个地方(q*q的矩阵,maps[i][j]表示地点i到j花费的时间),她接到m个任务

每个任务i,该任务的执行的地点为pi,执行人员到达花费时间ti(也是该任务i开始的时间),完成该任务

花费时间di,执行人员完成了上一个任务下能去做下一个任务(即执行人员要想做第j个任务,他完成上一

个任务i花的所有时间+到达第j个任务发生的地点所花的时间<=第j个任务开始的时间);求最少需要多少

执行人员去执行这m个任务


用Floyd来找到地点i到地点j花费的最少时间即最短路(即可以缩短执行人员从i地到j地在路上的时间)

然后用二分匹配,注意二分图的X集合和Y集合都是任务的编号,而不是任务执行的地点如果第i个任务完成

后还能做第j个任务,则i与j之间有一条连线G[i][j] = 1

接下来就是二分匹配的最小覆盖路经问题了

#include<stdio.h>
#include<math.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#define N 310
#define INF 0x3f3f3f3f

using namespace std;

struct node
{
    int p, t, d;
}node[N];

int G[N][N], maps[30][30], vis[N], used[N];
int m, q;

bool Find(int u)
{
    int i;
    for(i = 1 ; i <= m ; i++)
    {
        if(!vis[i] && G[u][i])
        {
            vis[i] = 1;
            if(!used[i] || Find(used[i]))
            {
                used[i] = u;
                return true;
            }
        }
    }
    return false;
}

void Floyd()
{
    int i, j, k;
    for(k = 1 ; k <= q ; k++)
    {
        for(i = 1 ; i <= q ; i++)
        {
            for(j = 1 ; j <= q ; j++)
            {
                if(maps[i][k] + maps[k][j] < maps[i][j])
                    maps[i][j] = maps[i][k] + maps[k][j];
            }
        }
    }
}

int main()
{
    int i, j;
    while(scanf("%d%d", &q, &m), q + m)
    {
        memset(G, 0, sizeof(G));
        for(i = 1 ; i <= q ; i++)
        {
            for(j = 1 ; j <= q ; j++)
              {
                  scanf("%d", &maps[i][j]);
                  if(maps[i][j] == -1)
                    maps[i][j] = INF;
              }
        }
        for(i = 1 ; i <= m ; i++)
            scanf("%d%d%d", &node[i].p, &node[i].t, &node[i].d);
        Floyd();
        for(i = 1 ; i <= m ; i++)
        {
            for(j = 1 ; j <= m ; j++)
            {
                if(i == j)continue;
                if(node[i].d + maps[node[i].p][node[j].p] + node[i].t <= node[j].t)
                    G[i][j] = 1;//****注意此处二分图的两个集合元素是任务的编号而不是地点block
            }
        }
        int ans = 0;
        memset(used, 0, sizeof(used));
        for(i = 1 ; i <= m ; i++)
        {
            memset(vis, 0, sizeof(vis));
            if(Find(i))
                ans++;
        }
        printf("%d\n", m - ans);
    }
    return 0;
}

 

 
posted @ 2015-09-26 12:06  午夜阳光~  阅读(317)  评论(0编辑  收藏  举报