转化一下题目。
给定一些点
1
1
1~
n
n
n,求最多能删除多少个点而且满足点
1
,
2
,
3
1,2,3
1,2,3直接或者间接连通
如果删除的是边的话
先建图,边权均为1。
算出
1
,
2
,
3
1,2,3
1,2,3中每一个点到另外两个点的最短路的长度和,三个点的加起来除以
2
2
2就是最少剩下的边数
然而现在删除的是点。
实际上现在就是要用最少的点让
1
,
2
,
3
1,2,3
1,2,3相连。
空想比较难,分类画个图吧?
先把让
1
,
2
,
3
1,2,3
1,2,3相连的最少点数当作现在要求的答案
如果已经连上了,显然为
3
3
3
如果只有两个直接连上,从孤点跑最短路取
m
i
n
_
l
e
n
g
t
h
+
1
min\_length+1
min_length+1即可
如果三个不直接相连,在间接相连后的图里面肯定有一个点,它到三个点的路径没有重合部分
反向最短路三次。
实际上三个不直接相连的做法在前两个也适用。以上。
ps 另外有一种思路就是尽量利用最短路重复点虽然会T
记得初始化(
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstring>
#include<cctype>
using namespace std;
#define add_edge(a,b) nxt[++tot]=head[a],head[a]=tot,to[tot]=b
const double EPS=1e-6;
int T,N,tot=0;
bool vis[205]={};
int dis[205]={};
int Xi[205]={},Yi[205]={},Ri[205]={};
int head[205]={},nxt[40005]={},to[40005]={};
int sum[205]={};
int ans=0x3f3f3f3f;
double dist(int x,int y)
{
double temp0=Xi[x]-Xi[y];
double temp1=Yi[x]-Yi[y];
return sqrt(temp0*temp0+temp1*temp1);
}
void calcIf(int x,int y)
{
if(dist(x,y)-Ri[x]-Ri[y]>0)return;
add_edge(x,y);
add_edge(y,x);
}
#define PII pair<int,int>
priority_queue<PII,vector<PII>,greater<PII> >Q;
void dijkstra(int S)
{
memset(vis,0,sizeof(vis)); memset(dis,0x3f,sizeof(dis));
Q.push(make_pair(0,S)); dis[S]=0;
while(!Q.empty())
{
int x=Q.top().second; Q.pop(); vis[x]=1;
for(int i=head[x];i;i=nxt[i])
{
if(dis[to[i]]<=dis[x]+1)continue;
dis[to[i]]=dis[x]+1;
if(vis[to[i]])continue;
Q.push(make_pair(dis[to[i]],to[i]));
}
}
for(int i=1;i<=N;++i)
{
if(dis[i]==0x3f3f3f3f)sum[i]=0x3f3f3f3f;
else sum[i]+=dis[i];
}
}
int main()
{
scanf("%d",&T);
while(T--) {
tot=0;
memset(sum,0,sizeof(sum));
memset(head,0,sizeof(head));
scanf("%d",&N);
for(int i=1;i<=N;++i) {
scanf("%d%d%d",&Xi[i],&Yi[i],&Ri[i]);
for(int j=1;j<i;++j) {
calcIf(j,i);
}
}
dijkstra(1);
dijkstra(2);
dijkstra(3);
ans=0x3f3f3f3f;
for(int i=1;i<=N;++i)ans=min(ans,sum[i]);
if(ans>=0x3f3f3f3f)printf("-1\n");
else printf("%d\n",N-ans-1);
}
return 0;
}