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;
}

 

posted @ 2025-03-25 12:41  Annaprincess  阅读(16)  评论(0)    收藏  举报