Aizu 2251 Merry Christmas(二分图最大匹配+Floyd)

Merry Christmas

Time Limit : 8 sec, Memory Limit : 65536 KB

Problem J: Merry Christmas

International Christmas Present Company (ICPC) is a company to employ Santa and deliver presents on Christmas. Many parents request ICPC to deliver presents to their children at specified time of December 24. Although same Santa can deliver two or more presents, because it takes time to move between houses, two or more Santa might be needed to finish all the requests on time.

Employing Santa needs much money, so the president of ICPC employed you, a great program- mer, to optimize delivery schedule. Your task is to write a program to calculate the minimum number of Santa necessary to finish the given requests on time. Because each Santa has been well trained and can conceal himself in the town, you can put the initial position of each Santa anywhere.

Input

The input consists of several datasets. Each dataset is formatted as follows.

N M L
u
1 v1 d1
u2 v2 d2
.
.
.
uM vM dM
p1 t1
p2 t2
.
.
.
pL tL

The first line of a dataset contains three integer, N , M and L (1 ≤ N ≤ 100, 0 ≤ M ≤ 1000, 1 ≤ L ≤ 1000) each indicates the number of houses, roads and requests respectively.

The following M lines describe the road network. The i-th line contains three integers, ui , vi , and di (0 ≤ uivi ≤ N - 1, 1 ≤ di ≤ 100) which means that there is a road connecting houses ui and vi with di length. Each road is bidirectional. There is at most one road between same pair of houses. Whole network might be disconnected.

The next L lines describe the requests. The i-th line contains two integers, pi and ti (0 ≤ pi ≤ N - 1, 0 ≤ ti ≤ 108 ) which means that there is a delivery request to house pi on time ti . There is at most one request for same place and time. You can assume that time taken other than movement can be neglectable, and every Santa has the same speed, one unit distance per unit time.

The end of the input is indicated by a line containing three zeros separated by a space, and you should not process this as a test case.

Output

Print the minimum number of Santa necessary to finish all the requests on time.

Sample Input

3 2 3
0 1 10
1 2 10
0 0
1 10
2 0
3 2 4
0 1 10
1 2 10
0 0
1 10
2 20
0 40
10 10 10
0 1 39
2 3 48
3 5 20
4 8 43
3 9 10
8 9 40
3 4 5
5 7 20
1 7 93
1 3 20
0 0
1 100000000
2 100
3 543
4 500
5 400
6 300
7 200
8 100
9 100
0 0 0

Output for the Sample Input

2
1
4
题意:给出无向图和某些需要Santa在规定时间到达的点,求所需的最小Santa数量。

思路:n足够小,可用Floyd求任意两点的距离,如果两个要求request[i], request[j]能由同一个Santa送达,则
d[request[i].num][request[j].num]<=request[i].time-request[j].time。建立二分图,二分均为0,1...l-1,若两点能用同一个Santa送达则建边。如果二分图不建边,需要的Santa为l,如果有一个匹配,则需要Santa为l-1,因此最小的Santa数量为l-二分图的最大匹配。(二分图顶点数应为l+l,而不能是n+n,wa了n次好难过)

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <math.h>
#include <vector>

using namespace std;

struct request{int num, time;}re[2009];
vector<int> g[2009];
int match[2009];
bool used[2009];
int n, m, l;
int INF=999999999;
int d[209][209];
void add_edge(int u, int v)
{
    g[u].push_back(v);
    g[v].push_back(u);
}
bool dfs(int v)
{
    used[v]=true;
    for(int i=0; i<g[v].size(); i++)
    {
        int u=g[v][i], w=match[u];
        if(w<0 || !used[w] && dfs(w))
        {
            match[v]=u;
            match[u]=v;
            return true;
        }
    }
    return false;
}
int bipartite_matching()
{
    int res=0;
    memset(match, -1, sizeof(match));
    for(int v=0; v<l+l; v++)
    {
        if(match[v]<0)
        {
            memset(used, 0, sizeof(used));
            if(dfs(v))
                res++;
        }
    }
    return res;
}
void Floyd()
{
    for(int k=0; k<n; k++)
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++)
                d[i][j]=min(d[i][j], d[i][k]+d[k][j]);
}
int main()
{
    int f, t, dis;
    while(~scanf("%d%d%d", &n, &m, &l))
    {
        if(!(n+m+l)) break;
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++)
                d[i][j]=INF;
        for(int i=0; i<2009; i++)
            g[i].clear();
        for(int i=0; i<m; i++)
        {
            scanf("%d%d%d", &f, &t, &dis);
            d[f][t]=dis;
            d[t][f]=dis;
        }
        for(int i=0; i<n; i++)
        {
            d[i][i]=0;
        }
        Floyd();
        for(int i=0; i<l; i++)
        {
            scanf("%d%d", &re[i].num, &re[i].time);
        }
        for(int i=0; i<l; i++)
        {
            for(int j=0; j<l; j++)
            {
                if(i==j) continue;
                if(d[re[i].num][re[j].num]<=re[j].time-re[i].time)
                {
                    add_edge(i, j+l);
                }
            }
        }
        printf("%d\n", l-bipartite_matching());
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值