3月24日练习
第五题:最优配餐


考点:多源bfs
当权重(每条边开销为1)的最短路问题可以用bfs
做法:将每个分店先入队,然后依次对每个分店向前后左右走,只要能到达客户那里那么当前饭店就是距离客户最近的饭店,满足了这个客户以后要对这个用户标注不重复遍历。
算法思想:

#include<bits/stdc++.h>
using namespace std;
//方向向量
int dx[4] ={0,0,-1,1};
int dy[4]={1,-1,0,0};
const int N=1006;
struct restaurant{
int l;//列
int h;//行
int step;//经过多少步
};
bool vis[N][N];//当他为true时表示是障碍点,或者是饭店经过已经扫描过的点
//用户订单数和位置可以通过地图上的点带有的权值表示
//即graph[i][j]表示(i,j)上所有用户下单的数目总和是graph[i][j]
int graph[N][N];
int n,m,k,d;
queue<restaurant>dl;//饭店队列
long long int ans;
bool check(int p,int q){//检查(p,q)这个点是否能走
if(vis[q][p]){//已经走过
return false;
}
if(p<1||p>n||q<1||q>n) {//越界
return false;
}
return true;
}
void bfs(){
while(!dl.empty()){
restaurant a=dl.front();
dl.pop();
//前后左右四个方向走(其实有点像那个海岛淹没的题目)
for(int i=0;i<4;i++) {
int xx=a.l+dx[i];
int yy=a.h+dy[i];
if(check(xx,yy)){
//只要是能经过这个点就需要放入队列,并且标注该点已经访问
vis[yy][xx]=true;
restaurant b;
b.h=yy;
b.l=xx;
b.step=a.step+1;
dl.push(b);
if(graph[yy][xx]){//是顾客
ans=ans+b.step*graph[yy][xx];
}
}
}
}
}
int main(){
cin>>n>>m>>k>>d;
//饭店
for(int i=0;i<m;i++) {
restaurant a;
cin>>a.l;
cin>>a.h;
a.step=0;//初始1步还未走
dl.push(a);
vis[a.h][a.l]=true;
}
//顾客
int x,y,c;
for(int i=0;i<k;i++){
cin>>x>>y>>c;
graph[y][x]+=c;
}
//障碍
for(int i=0;i<d;i++){
cin>>x>>y;
vis[y][x]=true;
}
bfs();
cout<<ans;
return 0;
}
第一题:无线网络

考点:bfs+邻接表建图
对于这种权值为1的最小值问题优先考虑bfs
完整代码:
/*
对题目理解:
1.原有路由器n个,可选择的新增路由器m个但是最多选择k个
2.两个路由器之间的距离小于等于r才能通信-->所以可以将能通信的所有路由器连接成一个图用邻接表存储
3.求第一个->第二个路由之间的路由至少是多少个才能通信
有点偏动态规划的想法求最值
4.可以设计dist数组,dist[i][j]表示从第一个路由器到第i个路由器 其中新增j个路由器经过的路由器个数(不算起点)
5.最短路径(最少路由器个数问题,每一个路由器权值为1)-->bfs
6.队列 里面放的元素形如{i,j}表示从第一个路由器到第i个路由器其中经过了j个新增路由器
*/
#include<bits/stdc++.h>
using namespace std;
const int N=206;//路由器最多不超过200个
int n,m,k,r;
struct {
int x;//列
int y;//行
}router[N];
//邻接表存图
int h[N];//头指针
int e[2*N];
int idx;
int ne[2*N];
int dist[N][N];
typedef pair<int,int> PII;
void add(int a,int b){//很重要!
e[idx]=b;
ne[idx]=h[a];
h[a]=idx++;
}
int bfs(){
int ans=260;
memset(dist,300,sizeof(dist));
dist[1][0]=0;
queue<PII>q;
q.push({1,0});
while(!q.empty()){
PII a=q.front();
q.pop();
int anum=a.first;//当前路由器编号
for(int i=h[anum];i!=-1;i=ne[i]) {
int bnum=e[i];//相邻的路由器编号
int anew=a.second;//当前已经选择了多少新路由器
if(bnum>n){//相邻的这个路由器是新增
anew++;
}
if(anew<=k) {//可以新增
if(dist[bnum][anew]>dist[anum][a.second]+1) {//如果相邻的这个路由器可以用当前的更新-->就要更新,并且放进队列,因为可能在最短路上
dist[bnum][anew]=dist[anum][a.second]+1;
q.push({bnum,anew}) ;
}
}
}
}
for(int i=0;i<=k;i++){
ans=min(ans,dist[2][i]);
}
return ans-1;
}
bool check(int i,int j) {
if((router[i].x-router[j].x)*(router[i].x-router[j].x)+(router[i].y-router[j].y)*(router[i].y-router[j].y)<=r*r){
return true;
}
return false;
}
int main(){
memset(h,-1,sizeof(h));//初始化头指针
cin>>n>>m>>k>>r;
//用路由器编号代表路由器
//1~n号路由器是已经有的路由器
for(int i=1;i<=n;i++) {
cin>>router[i].x>>router[i].y;
}
//n+1~n+m号路由器是可以选择的新增路由器
for(int i=n+1;i<=n+m;i++) {
cin>>router[i].x>>router[i].y;
}
//两台路由器之间的距离小于等于r就可以通信,把能通信的所有路由器连成图
for(int i=1;i<=n+m;i++) {
for(int j=1;j<=n+m;j++){
if(check(i,j)){//能通信
//因为是无向图所以两个方向都要连
add(i,j);
add(j,i);
}
}
}
cout<<bfs();
return 0;
}

浙公网安备 33010602011771号