hdu3832(2011 Multi-University Training Contest 1 - Host by HNU )

来源:互联网 发布:mmd美腿战队数据 编辑:程序博客网 时间:2024/06/05 07:55

题意:给n个点,求将前三个点连接起来的使用的最少的点的个数(每个点都有半径,两个点相连接表示两个的半径和大于或等于两点间的距离)。

思路:我没有想出该怎么做,想了很久,后来看了题解,题解用的是最短路做。开始我尝试用最小生成树做。但是不知道该怎么弄。到最后只有用DFS我可能才能做出来。怕超时于是放弃了。其实最小生成树也给了我很大的启示。判断点的联通用最小生成树,从这里也可以看到我学算法不具有灵活性,不会转换模型。后来用的是求最短路的方法。以三个点分别为原点然后求其的最短路。然后找到一个点到三个点的最短的距离。得解。

上代码:

#include<cstdio>
#include<math.h>
using namespace std;
struct node{
int x,y;
int r;
};
node a[210];
int g[210][210],value;
int dis(node x1,node x2){
if((x1.x-x2.x)*(x1.x-x2.x)+(x1.y-x2.y)*(x1.y-x2.y)<=(x1.r+x2.r)*(x1.r+x2.r))
return 1;
return 0;
}
int maxint=10000000;
int d[3][210],vis[210];
void spfa(int n,int s){
int queue[1001],i,h,r;
for(i=0;i<=n-1;i++){
d[s][i]=maxint;
vis[i]=0;
}
d[s][s]=0;
h=0;r=1;
queue[0]=s;
vis[s]=1;
while(h!=r){
int u=queue[h++];
vis[u]=0;
for(i=0;i<=n-1;i++){
if(d[s][i]>d[s][u]+g[u][i]){
d[s][i]=d[s][u]+g[u][i];
if(!vis[i]){
vis[i]=1;
queue[r++]=i;
}
}
}
}
}
main(){
int t;
int n,i,j,min;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(i=0;i<=n-1;i++){
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].r);
}
for(i=0;i<=n-1;i++){
for(j=0;j<=n-1;j++){
g[i][j]=10000000;
if(dis(a[i],a[j])){
g[i][j]=1;
}
}
}
for(i=0;i<=2;i++){
spfa(n,i);
}
min=10000000;
for(i=0;i<=n-1;i++){
if(min>d[0][i]+d[1][i]+d[2][i]){
min=d[0][i]+d[1][i]+d[2][i];
}

}
if(min+1>n)
printf("-1\n");
else{
printf("%d\n",n-min-1);
}
}
}