码迷,mamicode.com
首页 > 其他好文 > 详细

poj3216

时间:2016-07-01 19:54:14      阅读:177      评论:0      收藏:0      [点我收藏+]

标签:

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;
}

 

poj3216

标签:

原文地址:http://www.cnblogs.com/shenben/p/5633963.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!