//这个题目第一次遇到的时候不会。。然后看了大神的解题报告才懂的。。
//N个城市,M条路。。有Q个任务。。,求最少需要几个人才能完成任务。。先用FLOYD出任意两点的最短距离、、然后根据每个任务的时间排序。。然后拆点建边、、
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
#define maxn 2001
const int inf=1000000001;
bool mark[maxn];
int g[maxn][maxn];
int map[maxn][maxn];
int used[maxn][maxn];
int id[maxn][maxn];
int m,n,k,x,y;
int mk[maxn];
//从X集合中的顶点u出发用深度优先的策略寻找增广路
//(这种增广路只能使当前的匹配数增加1)
int nx, ny; //X和Y集合中顶点的个数
int cx[maxn] , cy[maxn];
//cx[i]表示最终求得的最大匹配中与Xi匹配的Y顶点, cy[i]同理
int path(int u)
{
 for(int v=0; v<ny; v++) //考虑所有Yi顶点v
 {
  if(map[u][v]&&!mk[v])
  {
   mk[v]=1;
   //如果v没有匹配,或者如果v已经匹配了,
   //但从y[v]出发可以找到一条增广路
   if(cy[v]==-1|| path(cy[v]))
   {
    cx[u] = v; //把v匹配给u
    cy[v] = u; //把u匹配给v
    return 1; //找到可增广路
   }
  }
 }
 return 0 ; //如果不存在从u出发的增广路
}
int MaxMatch() //求二部图最大匹配的匈牙利算法
{
 int res=0;
 memset(cx,0xff,sizeof(cx)); //从0匹配开始增广
 memset(cy,0xff,sizeof(cy));
 for(int i=0; i<=nx; i++)
 {
  if(cx[i]==-1) //从每个未盖点出发进行寻找增广路
  {
   memset(mk,0,sizeof(mk));
   res+=path(i); //每找到一条增广路,可使得匹配数加1
  }
 }
 return res;
}

typedef struct

 int x,y;
}Point;
Point point[1002];
int cmp(const void *p,const void *q)
{  
 Point *a,*b; 
 a=(Point *)p;
 b=(Point *)q; 
 return a->y-b->y;
}
int main()
{
 int i,j,k,m,n,q;   
 int x,y,z;
 int T=0,t; 
 scanf("%d",&t); 
 while(t--)  
 {      
  memset(map,0,sizeof(map));
  memset(used,0,sizeof(used));
        scanf("%d%d%d",&n,&m,&q);   
  nx=ny=q;//X集和Y集都是Q个元素。。
  for(i=0;i<n;i++)   //floyd 初始化
        {        
   for(j=0;j<n;j++)    
    g[i][j]=inf;
   g[i][i]=0;     
  }     
  for(i=0;i<m;i++)
  {         
   scanf("%d%d%d",&x,&y,&z); 
   if(g[x][y]>z)
    g[x][y]=g[y][x]=z;
  }      
  for(k=0;k<n;k++)  
  {         
   for(i=0;i<n;i++)  
   {             
    for(j=0;j<n;j++) 
    {                
     if(g[i][j]>g[i][k]+g[k][j])
      g[i][j]=g[i][k]+g[k][j]; 
    }         
   }     
  }     
  for(i=0;i<q;i++) 
  {        
   scanf("%d%d",&point[i].x,&point[i].y); 
  }    
  qsort(point,q,sizeof(point[0]),cmp); 
  for(i=0;i<q;i++)    //最小路径覆盖,把一个点拆成入点和出点。出点与入点建边即可
  {         
   for(j=i+1;j<q;j++) 
   {        
    if(point[j].y-point[i].y>=g[point[i].x][point[j].x])//符合条件就连起来。。 
    {                
     map[i][j]=1;
    }       
   }  
  }   
  printf("Case %d: ",++T);
  printf("%d\n",q-MaxMatch()-1);//减去哈利波特
 } 
 return 0;

posted on 2012-02-03 21:41  →木头←  阅读(244)  评论(0编辑  收藏  举报