POJ 3216 Repairing Company【二分图最小路径覆盖】

题意: 告诉你 Q 格街区,一共有 M d 个任务分布在这Q 个街区里面,知道了每个任务的开始时间和需要一个人的完成时间,

     问最少需要派多少人才能做完所有的任务。

分析: 求二分图的最小路径覆盖,分两种情况

         ① 两个第 I  个任务和 第 J g个任务在同一街区,如果满足 t[i]+d[i]<=t[j]  那么两个任务构成一个匹配,

    即第I 个任务和 第J 个任务可由同一个人先后完成,

   ②两个任务在不同街区,如果满足 t[i]+d[i]+dis[i][j]<=t[j],那么两任务亦构成一个匹配。

       求出最大匹配,最小路径覆盖即为m - 最大匹配

        其中每个点之间的最短路径可以通过floyd求得  

View Code
#include<stdio.h>
#include<string.h>
#define clr(x)memset(x,0,sizeof(x))
struct node
{
    int to,next;
}q[100000];
struct pe
{
    int bl,s,d;
}p[202];
int head[202];
int tot;
int link[202];
int v[202];
void add(int s,int u)
{
    q[tot].to=u;
    q[tot].next=head[s];
    head[s]=tot++;
}
int find(int x)
{
    int i,k;
    for(i=head[x];i;i=q[i].next)
    {
        k=q[i].to;
        if(!v[k])
        {
            v[k]=1;
            if(link[k]==0||find(link[k]))
            {
                link[k]=x;
                return 1;
            }
        }
    }
    return 0;
}
int g[22][22];
int main()
{
    int sum,i,j,k,Q,m,a,b,c;
    while(scanf("%d%d",&Q,&m),Q&&m)
    {
        for(i=1;i<=Q;i++)
            for(j=1;j<=Q;j++)
                scanf("%d",&g[i][j]);
        for(k=1;k<=Q;k++)
            for(i=1;i<=Q;i++)
            {
                if(g[i][k]!=-1)
                    for(j=1;j<=Q;j++)
                        if(g[k][j]!=-1&&(g[i][k]+g[k][j]<g[i][j]||g[i][j]==-1))
                            g[i][j]=g[i][k]+g[k][j];
            }
        for(i=1;i<=m;i++)
            scanf("%d%d%d",&p[i].bl,&p[i].s,&p[i].d);
        clr(link);
        clr(head);
        tot=1;
        for(i=1;i<=m;i++)
            for(j=1;j<=m;j++)
            if(i!=j)
            {
                if(p[i].d+p[i].s+g[p[i].bl][p[j].bl]<=p[j].s)
                    add(i,j);
            }
        sum=0;
        for(i=1;i<=m;i++)
        {
            clr(v);
            if(find(i))
                sum++;
        }
        printf("%d\n",m-sum);
    }
    return 0;
}
posted @ 2012-04-23 21:12  'wind  阅读(225)  评论(0编辑  收藏  举报