题目描述:
解题思路:
我们可以看作是单源最短路问题!(从1到2)
一共是n+m个点,我们先逐个判断每两个点之间是否有边,只要是两个点之间距离小于等于r就用邻接表连接起来,并且是双向边。
dis[i][j]表示从1到i经过j个特殊点(新加的点)的最少需要点的个数,我们可以将每条边看作单位1,那么也就表示从1到i经过j个特殊点(新加的点)的最短路!
然后用bfs一层层去搜索更新,逐个判断是否满足条件,去更新。(详细看代码)
#include<bits/stdc++.h>
using namespace std;
const int N=210,M=N*N;
int n,m,k,r;
#define x first
#define y second
#define LL long long
//typedef pair<int,int> PLL;
#define PII pair<int,int>
PII w[N];
int e[M],ne[M],idx,h[N];
int dis[N][N];//dis[i][j]表示从1到i经过j个特殊点的最小经过的点的个数
int res=0x3f3f3f3f;
void add(int a,int b) //将边加入到邻接表中
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
return ;
}
bool check(PII a,PII b) //判断是否满足条件
{
LL x=a.x-b.x;
LL y=a.y-b.y;
return x*x+y*y<=(LL)(r*r);
}
void bfs()
{
queue<PII> q;
memset(dis,0x3f,sizeof(dis));
dis[1][0]=0;
q.push({1,0});
while(q.size())
{
PII t=q.front();
q.pop();
for(int i=h[t.x];i!=-1;i=ne[i]) //i是边的索引idx,e[i] 是连的那个点
{
int x=e[i],y=t.y;//x是搜索的下一个点,y是特殊点的个数
if(x>n) y++; //如果下一个点是特殊点,那么从当前点更新的话,y应该加一(下一个点本身)
if(y<=k) //如果y<=k 满足题目要求
{
if(dis[x][y]>dis[t.x][t.y]+1) //判断是否更短,然后更新
{
dis[x][y]=dis[t.x][t.y]+1;
q.push({x,y}); //放入队列
}
}
}
}
for(int i=0;i<=k;i++) //最后寻找增加0~k个特殊点的情况下,最短的路径
{
res=min(res,dis[2][i]);
}
res--; //减去第二个点本身
return ;
}
int main()
{
memset(h,-1,sizeof(h));
cin>>n>>m>>k>>r;
for(int i=1;i<=n+m;i++) cin>>w[i].x>>w[i].y;
for(int i=1;i<=n+m;i++)
for(int j=i+1;j<=n+m;j++)
if(check(w[i],w[j]))
add(i,j),add(j,i);
bfs();
cout<<res<<endl;
return 0;
}
- 遇到的问题:
(LL)r*r 与(LL)(r*r)不同:前者是long了第一个r然后再乘以r就扩展成long long,但是后者是先(r*r)这时候已经爆int了,所以再long long也出错了!
- #define 与typedef的区别: