专栏文章

题解:P5100 [JOI 2017 Final] 足球 / Soccer

P5100题解参与者 5已保存评论 4

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
4 条
当前快照
1 份
快照标识符
@minnx2db
此快照首次捕获于
2025/12/02 05:29
3 个月前
此快照最后确认于
2025/12/02 05:29
3 个月前
查看原文
很好的题!
考虑球只有两种状态,在空中(被人踢着),或者在地上(被人带着),所以考虑拆点。
在地上你可以向四个方向自由移动(花费 CC 的代价),也可以进入某种飞行状态(花费 BB 的代价),然后每次都花费 AA 的代价向一个固定方向走
一旦球落地了,那么必须要有一个人来接应这个球。所以再加上 C×KC \times KKK 是离落地这个点最近的球员的距离。
这样为啥是对的?因为如果有人踢过球再去控球的话,不如直接把球运过去来的痛快。
所以可以拆出来 5×H×W5 \times H \times W 个点,分别表示在地上,向 东/西/南/北 飞的状态,然后跑单源最短路就行了。
时间复杂度 Θ(HWlogHW)\Theta(HW \log HW),常数略大。
CPP
#include <bits/stdc++.h>
#define int long long
#define FAST ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
using namespace std;
/*
by qqqaaazzz
*/
int n,m;
int A,B,C;
int q;
pair<int,int> p[100010];
int dis[510][510];
int fx[] = {0,0,-1,1};
int fy[] = {-1,1,0,0};
vector<pair<int,int> > v[2000010];

int t(int x,int y,int id){
	return id*(n+1)*(m+1)+x*(m+1)+y;
}
bool vis[2000010];
int D[2000010];

void Dijkstra(int st){
	priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> q;
	q.push(make_pair(0,st));
	memset(D,0x3f,sizeof(D));
	memset(vis,0,sizeof(vis));
	D[st] = 0;
	while(!q.empty()){
		pair<int,int> p = q.top();
		q.pop();
		if(vis[p.second]) continue;
		vis[p.second] = true;
		for (auto i : v[p.second]){
			if(p.first+i.second<D[i.first]){
				D[i.first] = p.first+i.second;
				q.push(make_pair(D[i.first],i.first));
			}
		}
	}
	return;
}

signed main()
{
	cin >> n >> m;
	cin >> A >> B >> C;
	cin >> q;
	for (int i=1;i<=q;i++){
		cin >> p[i].first >> p[i].second;
	}
	//求出来每个点最近的球员
	memset(dis,0x3f,sizeof(dis));
	queue<pair<int,int> > Q;
	for (int i=1;i<=q;i++){
		dis[p[i].first][p[i].second] = 0;
		Q.push(p[i]);
	}
	while(!Q.empty()){
		pair<int,int> f = Q.front();
		Q.pop();
		for (int i=0;i<4;i++){
			int dx = f.first+fx[i];
			int dy = f.second+fy[i];
			if(dx>=0&&dx<=n&&dy>=0&&dy<=m&&dis[f.first][f.second]+1<dis[dx][dy]){
				dis[dx][dy] = dis[f.first][f.second]+1;
				Q.push({dx,dy});
			}
		}
	}
	
	for (int i=0;i<=n;i++){
		for (int j=0;j<=m;j++){
			for (int f=1;f<=4;f++){
				int dx = i+fx[f-1],dy = j+fy[f-1];
				if(dx>=0&&dx<=n&&dy>=0&&dy<=m){
					v[t(i,j,0)].push_back({t(dx,dy,0),C});
					v[t(i,j,f)].push_back({t(dx,dy,f),A});
				}
				v[t(i,j,0)].push_back({t(i,j,f),B});
				v[t(i,j,f)].push_back({t(i,j,0),dis[i][j]*C});
			}
		}
	}
	Dijkstra(t(p[1].first,p[1].second,0));
	cout << D[t(p[q].first,p[q].second,0)] << "\n";
	return 0;
}

评论

4 条评论,欢迎与作者交流。

正在加载评论...