//这个题目第一次遇到的时候不会。。然后看了大神的解题报告才懂的。。
//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;
}