第五题:最优配餐
考点:多源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;
}