zoukankan      html  css  js  c++  java
  • 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
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    算法-经典趣题-寻找假银币
    一天一个 Linux 命令(3):cat 命令
    算法-经典趣题-青蛙过河
    常用数据库有哪些?
    SpringBoot2.0入门教程(一) 快速入门,项目构建HelloWorld示例
    一天一个 Linux 命令(2):ls 命令
    算法-经典趣题-爱因斯坦阶梯问题
    一天一个 Linux 命令(1):vim 命令
    什么是开发环境、测试环境、UAT环境、仿真环境、生产环境?
    算法-经典趣题-渔夫捕鱼
  • 原文地址:https://www.cnblogs.com/shenben/p/5633963.html
Copyright © 2011-2022 走看看