poj3216

Repairing Company
Time Limit: 1000MS Memory Limit: 131072K
Total Submissions: 6947 Accepted: 1869

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 pi, ti 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

Source

求最少的修理工完成修理任务。
根据数据范围猜解法,很容易想到网络流啊,匹配神马的。。然后就悟了

是一个很裸的最小路径覆盖问题,然后就匈牙利啊随便就过了。。。
说一些可能错的地方吧:
1.一开始修理工可以在任何区域。
2.题目中“ has a deadline ti on any repairman’s arrival, which is also its starting time”这句话说明修理开始时间必须是ti,只要在ti之前到达i点所在块,但是一定要在ti开始修理。
3.两点间的路不一定是最短,所以要用floyd处理一下。

关于最小路径覆盖:
每个点拆成两个点分别在二分图的两侧,如果i可以到j,那么就建一条i'->j的边。求最大匹配。
最小路径数就是总点数减去匹配数。

简单的证明:总点数n,开始需要n条路径。i与j的匹配就意味着i与j所在的路径可以合并,那就减少一条路径。

所以求出最大的匹配数m,总路径就减少m条,也是最小的路径数了。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define N 210
int n,m,ans,q[N],t[N],d[N],g[N][N],e[N][N],link[N],vis[N];
int find(int u){
    for(int i=1;i<=m;i++){
        if(!vis[i]&&e[u][i]){
            vis[i]=1;
            if(!link[i]||find(link[i])){
                link[i]=u;
                return 1;
            }
        }
    }
    return 0;
}
void floyd(){
    for(int k=1;k<=n;k++){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                if(i!=j&&i!=k&&j!=k&&g[i][k]!=-1&&g[k][j]!=-1){
                    if(g[i][j]>g[i][k]+g[k][j]||g[i][j]==-1) 
                       g[i][j]=g[i][k]+g[k][j];
                }
            }
        }
    }
}
int main(){
    while(scanf("%d%d",&n,&m)==2&&n&&m){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                scanf("%d",&g[i][j]);
            }
        }
        floyd();
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&q[i],&t[i],&d[i]);
        }
        memset(e,0,sizeof e);
        memset(link,0,sizeof(link));
        for(int i=1;i<=m;i++){
            for(int j=1;j<=m;++j)if (i!=j){
                if(t[i]+d[i]+g[q[i]][q[j]]<=t[j]) e[i][j]=1;
            }
        }
        ans=m;
        for(int i=1;i<=m;i++){
            memset(vis,0,sizeof(vis));
            if(find(i)) ans--;
        }
        printf("%d\n",ans);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/shenben/p/5633963.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值