题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3832
题意:给出n个半径和圆心坐标已知的点,编号为1 -- n ,求连接1 ,2 , 3所需要的最少圆。
题目的难点在于转化,转化为枚举其他点到当前 3 个点的最小距离。即最短路径、
分析:给出的是圆的坐标,首先我们知道,如果一个圆和其他所有圆都没有交集,那么这个圆肯定不能连通其他圆,先排除这些,然后求剩下有交集的圆连通1,2,3,所需要最少的
圆,那么我们以圆的编号为点,任意两个有交集的圆建立一条长度为 1 的边,我们是不是就转化为求1,2,3三个点间的最短路,而求三个点间的最短路,我们可以画图试试是不是要
通过一个中间点求得的路径是最短的,那么问题得到了解决。
求最短路有很多算法,这个题目都可以,这里给出spfs实现:
代码:
#include <cstdio> #include <vector> #include <iostream> #include <stack> #include <cstdio> #include <string> #include <cstring> #include <cmath> #include <algorithm> #include <queue> using namespace std; const int inf = 0x3f3f3f3f; const int N = 300; struct Point { int x,y; int r; int num; }; Point a[N]; struct Node { int v,len; }; vector<Node> map[N]; int n; void spfa(int s,int dis[]) { int i; queue<int> q; for(i=0; i<N; i++) dis[i]=inf; dis[s]=0; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); for(i=0; i<map[u].size(); i++) { Node p=map[u][i]; if(dis[p.v]>dis[u]+p.len) { dis[p.v]=dis[u]+p.len; q.push(p.v); } } } } int main() { int dis1[N],dis2[N],dis3[N]; int T; scanf("%d",&T); while(T--) { for(int i=0;i<N;i++) map[i].clear(); scanf("%d",&n); memset(map,0,sizeof(map)); for(int i=0; i<n; i++) { scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].r); } for(int i=0;i<n;i++) { for(int j=i+1;j<n;j++) { int dist1=(a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y); int dist2=(a[i].r+a[j].r)*(a[i].r+a[j].r); if(dist1<=dist2) { Node p; p.v=j; p.len=1; map[i].push_back(p); p.v=i; map[j].push_back(p); } } } spfa(0,dis1); spfa(1,dis2); spfa(2,dis3); int ans=-1; for(int i=0;i<n;i++) { if(dis1[i]<inf&&dis2[i]<inf&&dis3[i]<inf) ans=max(ans,n-(dis1[i]+dis2[i]+dis3[i]+1)); } if(ans==inf) ans=-1; printf("%d\n",ans); } return 0; }