poj 3216 Repairing&nbs…

题意: 一家维修公司,服务的 Q 街区。每个街区有一定距离, 一天公司收到M修理任务,第i个任务发生在第i个街区, 并且每个任务都有起始时间 ti,完成一个任务需要di时间.修理工必须完成一个任务后,再去另一个. 问要完成这M个任务最少需要多少个修理工?

思路:有向图的最小路径覆盖。先用floyd求出两点间的最短距离,然后建图 若第j个街区任务的开始时间大于等于第i个街区的任务完成时间 + 路上花费时间 则i到j间连一条边 建立二分图 求最大匹配 。ans = 顶点数 - 最大匹配数。

//328K    79MS
#include
#include
#define Q 25
#define M 205
const int inf = 0x3f3f3f3f;
int mat[Q][Q],edge[M][M];//mat[][]为Q个街区间的距离 edge[i][j] = 1;为i到j有边
int n,m;
int link[M],vis[M];
struct point
{
    int pt,sta,end;//pt 顶点编号,sta开始时间,end完成的时间
}node[M];

bool DFS(int u)
{
    for (int v = 1;v <= m;v ++)
        if (edge[u][v]&&!vis[v])
        {
            vis[v] = 1;
            if (link[v] == -1 || DFS(link[v]))
            {
                link[v] = u;
                return true;
            }
        }
    return false;
}
int MaxMatch ()
{
    int res = 0;
    memset (link,-1,sizeof(link));
    for (int u = 1;u <= m;u ++)
    {
        memset (vis,0,sizeof(vis));
        if (DFS(u))
            res ++;
    }
    return res;
}
int main ()
{
    int i,j,k,t,d;
    while (scanf ("%d%d",&n,&m))
    {
        if (n == 0 && m == 0)
            break;
        memset (edge,0,sizeof(edge));
        for (i = 1;i <= n;i ++)
            for (j = 1;j <= n;j ++)
            {
                scanf ("%d",&mat[i][j]);
                if (mat[i][j] == -1)
                    mat[i][j] = inf;
            }
        for (i = 1;i <= m;i ++)
        {
            scanf ("%d%d%d",&node[i].pt,&node[i].sta,&d);
            node[i].end = node[i].sta + d;
        }
        for (k = 1;k <= n;k ++)          //floyd
            for (i = 1;i <= n;i ++)
                for (j = 1;j <= n;j ++)
                    if (mat[i][j] > mat[i][k]+mat[k][j])
                        mat[i][j] = mat[i][k]+mat[k][j];
        for (i = 1;i <= m;i ++)             //建图
            for (j = 1;j <= m;j ++)
                if (node[j].sta >= node[i].end+mat[node[i].pt][node[j].pt])
                    edge[i][j] = 1;
        int ans = MaxMatch();
        printf ("%d\n",m - ans);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值