aoj 2251 二分图匹配

题目链接:
http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2251

题目大意:
问最少安排几个圣诞老人送礼物。
给了一些点,之间存在一些路径。给出了一些点必须在一定的时刻有圣诞老人到达,圣诞老人可以从任何点出发。求最少的圣诞老人个数。

思路:
建图十分炫酷,本人太愚钝着实没看出来。。最坏情况下每一个点都需要一个圣诞老人,考虑怎么减少人数。对于每一个需要到达的点,考虑在到达之后能否在规定的时间内走到另一个点,如果可以的话,将这两个点连边。意味着这两个点只需要一个圣诞老人。那么此时最大匹配数就是能够节省的圣诞老人,最小的边覆盖就是所需要的最少的圣诞老人的个数。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
#define M 20009
const int INF = 0x3f3f3f3f;
typedef pair<int,int> pii;
int n,m,l;
int dis[M][M];
bool used[M];
int match[M];
vector<int> G[M];
vector<pii> qu;
void init()
{
    qu.clear();
    for(int i = 0;i < 2*n;i++)
    {
        for(int j = 0;j < 2*n;j++)
        {
            if(i == j) dis[i][j] = 0;
            else dis[i][j] = INF;
        }
    }
    for(int i = 0;i < M;i++) G[i].clear();
}
void add_edge(int u,int v)
{
    G[u].push_back(v);
    G[v].push_back(u);
}
void floyd()
{
    for(int k = 0; k < n;k++)
    {
        for(int i = 0;i < n;i++)
        {
            for(int j = 0;j < n;j++)
                dis[i][j] = min(dis[i][j],dis[i][k] + dis[k][j]);
        }
    }
}
void build()
{
    for(int i = 0;i < qu.size();i++)
    {
        for(int j = 0;j < qu.size();j++)
        {
            if(i == j) continue;
            pii a = qu[i], b = qu[j];
            int tmp = b.second - a.second;
            if(tmp >= dis[a.first][b.first])
            {
                add_edge(i,j+l);
            }
        }
    }
}
bool dfs(int u)
{
    for(int i = 0;i < G[u].size();i++)
    {
        int v = G[u][i];
        if(!used[v])
        {
            used[v] = true;
            if(match[v] < 0 || dfs(match[v]))
            {
                match[v] = u;
                return true;
            }
        }
    }
    return false;
}
int hungry()
{
    int res = 0;
    memset(match,-1,sizeof(match));
    for(int i = 0 ;i < l;i++)
    {
        memset(used,false,sizeof(used));
        if(dfs(i)) res++;
    }
    return res;
}
int main()
{
    while(scanf("%d %d %d",&n,&m,&l) == 3)
    {
        init();
        if(n == 0 && m == 0 && l == 0) break;
        for(int i = 0;i < m;i++)
        {
            int a,b,c;
            scanf("%d %d %d",&a,&b,&c);
            dis[a][b] = c;
            dis[b][a] = c;
        }
        for(int i = 0;i < l;i++)
        {
            int a,b;
            scanf("%d %d",&a,&b);
            qu.push_back(make_pair(a,b));
        }
        floyd();
        /*for(int i = 0;i < n;i++) { for(int j = 0;j < n;j++) printf("%d ",dis[i][j]); printf("\n"); }*/
        build();
        int tmp = hungry();
        //printf("debug -- tmp = %d\n",tmp);
        printf("%d\n",l - hungry());
    }
    return 0;
}

你可能感兴趣的:(aoj 2251 二分图匹配)