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
uvd1
uvd2
.
.
.
uM vM dM
pt1
pt2
.
.
.
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 ≤ ui < vi≤ 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

 

       题意:

       给出N(1 ~ 100),M(0 ~ 1000),L(1 ~ 1000),代表有 N 个地点,M 个条路,L 个目标。每个地点从0 ~ N-1标号,后给出 M 条路,每条路都是双向边,给出 A,B,V(1 ~ 100),代表A,B之间有一条时间为 V 的路。后给出需要完成的 L 个目标,每个目标给出地点 i 和必须所完成的时间 time(0 ~ 108)。问要如何安排访问次数,使达到所有的目标。

 

       思路:

       二分图最大匹配 + Floyd。分清楚要目的是什么,给出图的信息只是一个已知条件而已,要完成的是目标,如何安排访问路径来使访问次数最少,求最小路径覆盖。首先对图进行 floyd 一次,求出任意两点间的最短路,后每个目标访问点间看能否满足起点时间 + 最短路时间 <= 终点时间 连接起来。后求出最大匹配,再求出最小路径覆盖即可。

 

       AC:

#include <cstdio>
#include <string.h>
#define INF 99999999
using namespace std;

typedef struct {
    int num;
    int time;
}node;
int n,l;
int dis[105][105],w[1005][1005];
int linker[1005],vis[1005];
node no[1005];

void floyd() {
    for(int k = 0;k < n;k++)
        for(int i = 0;i < n;i++)
            for(int j = 0;j < n;j++)
                if(dis[i][k] < INF &&
                   dis[k][j] < INF &&
                   dis[i][j] > dis[i][k] + dis[k][j])
                   dis[i][j] = dis[i][k] + dis[k][j];
}

bool dfs(int u) {
    for(int v = 1;v <= l;v++)
        if(w[u][v] && !vis[v]) {
            vis[v] = 1;
            if(linker[v] == -1 || dfs(linker[v])) {
                linker[v] = u;
                return true;
            }
        }
    return false;
}

int hungary() {
    int res = 0;
    memset(linker,-1,sizeof(linker));
    for(int u = 1;u <= l;u++) {
        memset(vis,0,sizeof(vis));
        if(dfs(u)) res++;
    }
    return res;
}

int main() {
    int m;
    //freopen("test.in","r",stdin);
    while(~scanf("%d%d%d",&n,&m,&l) && (n + m + l)) {
        memset(w,0,sizeof(w));
        for(int i = 0;i < n;i++)
            for(int j = 0;j < n;j++) {
                dis[i][j] = INF;
                if(i == j) dis[i][j] = 0;
            }


        while(m--) {
            int a,b,val;
            scanf("%d%d%d",&a,&b,&val);
            dis[a][b] = val;
            dis[b][a] = val;
        }

        floyd();

        for(int i = 1;i <= l;i++)
            scanf("%d%d",&no[i].num,&no[i].time);

        for(int i = 1;i <= l;i++)
            for(int j = 1;j <= l;j++) {
            if(i == j) continue;
            int f = no[i].num,t = no[j].num;
            int ft = no[i].time,tt = no[j].time;
            if(ft + dis[f][t] <= tt) w[i][j] = 1;
        }

        printf("%d\n",l - hungary());
    }
    return 0;
}

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值