CCF 201409-4 最优配餐 100分(bfs)

题目来源:- 计算机软件能力认证考试系统

刚开始的思路:将每个收货点作为目标点,把送货点全部入队列,进行bfs,每次计算出一个结果,把每次迭代的结果相加得出最后答案。这种思路会导致运行超时,可能因为迭代次数过多。

60分代码:

#include<bits/stdc++.h>

using namespace std;
const int MAX=1000;
int n,m,k,d;
bool visited[MAX+10][MAX+10];
int dirX[]= {-1,1,0,0};
int dirY[]= {0,0,-1,1};
int weight[MAX+10];

struct Map {
	int x,y,sum;
	Map() {}
	Map(int xx, int yy, int s=0):x(xx),y(yy),sum(s) {}
} sell[MAX*MAX+10],buy[MAX*MAX+10],del[MAX*MAX+10];

int BFS(int destx, int desty, int destw) {
	queue<Map> q;
	
	memset(visited,false,sizeof(visited)); //每次bfs都重新初始化访问标记数组
	for(int i=1; i<=d; i++)
		visited[del[i].x][del[i].y]=true;

	for(int i=1; i<=m; i++)     //每次bfs都要将送货点入队
		q.push(sell[i]);

	while(!q.empty()) {
		Map cur=q.front();
		q.pop();
		visited[cur.x][cur.y]=true;

		if(cur.x==destx && cur.y==desty)
			return cur.sum*destw;

		for(int i=0; i<4; i++) {
			int x=cur.x+dirX[i],y=cur.y+dirY[i];
			if(x<1 || x>n || y<1 || y>n || visited[x][y])
				continue;
				
			visited[x][y]=true;
			q.push(Map(x,y,cur.sum+1));
		}
	}
	return 0;
}

int main() {

	cin>>n>>m>>k>>d;
	int x,y,w;
	for(int i=1; i<=m; i++) {
		cin>>x>>y;
		sell[i]=Map(x,y);
	}

	for(int i=1; i<=k; i++) {
		cin>>x>>y>>weight[i];
		buy[i]=Map(x,y);
	}
	
	for(int i=1; i<=d; i++) {
		cin>>x>>y;
		del[i]=Map(x,y);
	}
	
	long long ans=0;
	for(int i=1; i<=k; i++)
		ans+=BFS(buy[i].x, buy[i].y, weight[i]); //将每次bfs的结果相加得到答案

	cout<<ans;
	return 0;
}

 

改进:将所有送货点在输入时就全部入队,使用一个权重数组,记录收货点的权重,不是收货点的权重记为0。这样每次遍历到不是收货点的结点,只会加0,而不是加对应的权重*距离。

100分代码:

#include<bits/stdc++.h>

using namespace std;

const int MAX=1005;
int n,m,k,d;
bool visited[MAX][MAX];
int dirX[]= {-1,1,0,0};
int dirY[]= {0,0,-1,1};
long long weight[MAX][MAX];

struct Map {
	int x,y;
	long long sum;
	Map(int xx, int yy, int s=0):x(xx),y(yy),sum(s) {}
};

queue<Map> q;

long long BFS() {
	long long ans=0;
	
	while(!q.empty()) {
		Map cur=q.front();
		q.pop();
		visited[cur.x][cur.y]=true;

		for(int i=0; i<4; i++) {
			int x=cur.x+dirX[i],y=cur.y+dirY[i];
			if(x<1 || x>n || y<1 || y>n || visited[x][y])
				continue;
				
			visited[x][y]=true;
			ans+=weight[x][y]*(cur.sum+1);  //下一个结点不是收货点就加0,是收货点就加权重*距离
			q.push(Map(x,y,cur.sum+1));
		}
	}
	return ans;
}


int main() {
	ios::sync_with_stdio(false);
	
	cin>>n>>m>>k>>d;
	int x,y,w;
	for(int i=1; i<=m; i++) {
		cin>>x>>y;
		q.push(Map(x,y));  //在输入时就全部入队
	}

	for(int i=1; i<=k; i++) {
		cin>>x>>y>>w;
		weight[x][y]+=w;   //可能有多个收货点在同一坐标,权重要累积计算
	}
	
	for(int i=1; i<=d; i++) {
		cin>>x>>y;
		visited[x][y]=true; //记录不可达结点
	}

	cout<<BFS();
	return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值