[JOI 2017 Final] 足球 (建图,最短路)

题面

题解

我们可以总结出球的两种状态,要么自己飞,要么在球员脚下被带飞。

自己飞的情况下,他只能单向直线运动,每一步代价为A,被带飞可以乱走,每一步代价为C。

从自己飞到被带飞需要一个距离自己最近的球员过来,代价为 dis_{i,j}\cdot C,对于每个格点,这个代价都是确定的,因为球不可能两次到同一个球员脚下,所以球员就相当于一次性的工具人,输入后bfs处理 dis_{i,j} 就可以了。

从被带飞到自己飞需要踢一脚,给它自由,代价为B。

那么我们可以把每个格点拆成5个点,然后建个图。

自己飞要四个点,分别表示四个方向,每个点朝那个方向的下一个同类点连一条单向边,权值为A,这样就可以模拟出单向运动了。

被带飞就需要单独一个点,向四个方向的带飞点连双向边,权值为C,这样球就可以乱走了。

自己飞的四个点向被带飞的一个点分别连一条单向边,权值为 dis_{i,j}\cdot C ,表示球员跑过来,把它带飞。

被带飞的一个点向自己飞的四个点分别连一条单向边,权值为 B,表示分别向四个方向踢一脚的情况。

这样就可以直接求最短路了。

不推荐用 Slow Path Finding Algorithm。

CODE

注意,实际行数列数是 ≤ 501 的,总共有 251001 个点,特别坑

#include<cstdio>
#include<cstring>
#include<vector>
#include<stack>
#include<queue>
#include<algorithm>
#include<map>
#include<set>
#include<cmath>
#include<bitset>
#include<iostream>
#define MAXN 251010
#define LL long long
#define ULL unsigned LL
#define rg register
#define lowbit(x) (-(x) & (x))
#define ENDL putchar('\n')
#define DB double
#define bs bitset<105>
//#pragma GCC optimize(2)
//#pragma G++ optimize(3) 
//#define int LL
using namespace std;
char char_read_before = 1;
inline int read() {
	int f = 1,x = 0;char s = char_read_before;
	while(s < '0' || s > '9') {if(s == '-') f = -1;s = getchar();}
	while(s >= '0' && s <= '9') {x = x * 10 - '0' + s;s = getchar();}
	char_read_before = s;return x * f;
}
template<typename T__>
inline T__ Abs(T__ x) {return x < 0 ? -x:x;}
int zxy; // 用来膜的
int n,m,i,j,s,o,k,h,w,N,S,T;
int x[MAXN],y[MAXN];
int dpp[505][505];
bool v[505][505];
int dx[4] = {0,0,-1,1};
int dy[4] = {-1,1,0,0};
struct itn{
	int x,y,s;
	itn(){x=y=s=0;}
	itn(int X,int Y,int S){x=X;y=Y;s=S;}
};
queue<itn> b;
int L,R,U,D;
LL A,B,C;
struct it{
	int v;
	LL w;
	it(){v=w=0;}
	it(int V,LL W){v = V;w = W;}
};
vector<it> g[MAXN*5];
LL dp[MAXN*5] = {(LL)1e18};
bool f[MAXN*5];
inline int I(int x,int y) {return (x-1)*w + y;}
inline int bing(int a,int b) {return dp[a] < dp[b] ? a:b;}
int tre[MAXN*20],M;
inline void mt(int n){M=1;while(M < n+2) M <<= 1;}
inline void addt(int x,int y) {
	int s = M+x;tre[s] = y;s >>= 1;
	while(s) tre[s] = bing(tre[s<<1],tre[s<<1|1]),s >>= 1;
}
inline int allt() {return tre[1];}
void dij() {
	mt(N*5);
	dp[S] = 0;
	addt(S,S);
	for(int i = 1;i < N*5;i ++) {
		int t = allt();
		if(!t) break;
		f[t] = 1;
		for(int j = 0;j < g[t].size();j ++) {
			if(!f[g[t][j].v]) {
				dp[g[t][j].v] = min(dp[g[t][j].v],dp[t] + g[t][j].w);
				addt(g[t][j].v,g[t][j].v);
			}
		}
		addt(t,0);
	}
}
signed main() {
	h = read()+1;w = read()+1;
	N = h*w;
	A = read();B = read();C = read();
	n = read();
	for(int i = 1;i <= n;i ++) {
		x[i] = read()+1;y[i] = read()+1;
		dpp[x[i]][y[i]] = 0;
		v[x[i]][y[i]] = 1;
		b.push(itn(x[i],y[i],0));
	}
	while(!b.empty()) {
		itn t = b.front();
		b.pop();
		for(int i = 0;i < 4;i ++) {
			itn t1(t.x + dx[i],t.y + dy[i],t.s + 1);
			if(t1.x < 1 || t1.y < 1 || t1.x > h || t1.y > w || v[t1.x][t1.y]) continue;
			dpp[t1.x][t1.y] = t1.s;
			v[t1.x][t1.y] = 1;
			b.push(t1);
		}
	}
	S = I(x[1],y[1])+4*N;
	T = I(x[n],y[n])+4*N;
	for(int i = 1;i <= h;i ++) {
		for(int j = 1;j <= w;j ++) {
			LL pd = dpp[i][j]*C;
			int d1 = I(i,j),d2 = d1 + N,d3 = d2 + N,d4 = d3 + N,d5 = d4 + N;
			dp[d1] = dp[d2] = dp[d3] = dp[d4] = dp[d5] = (LL)1e17;
			if(i > 1) {
				g[d1].push_back(it(I(i-1,j),A));
				g[d5].push_back(it(I(i-1,j)+4*N,C));
			}
			if(i < h) {
				g[d2].push_back(it(I(i+1,j)+N,A));
				g[d5].push_back(it(I(i+1,j)+4*N,C));
			}
			if(j > 1) {
				g[d3].push_back(it(I(i,j-1)+2*N,A));
				g[d5].push_back(it(I(i,j-1)+4*N,C));
			}
			if(j < w) {
				g[d4].push_back(it(I(i,j+1)+3*N,A));
				g[d5].push_back(it(I(i,j+1)+4*N,C));
			}
			g[d1].push_back(it(d5,pd));
			g[d2].push_back(it(d5,pd));
			g[d3].push_back(it(d5,pd));
			g[d4].push_back(it(d5,pd));
			
			g[d5].push_back(it(d1,B));
			g[d5].push_back(it(d2,B));
			g[d5].push_back(it(d3,B));
			g[d5].push_back(it(d4,B));
		}
	}
	dij();
	printf("%lld\n",dp[T]);
	return 0;
} 

 

posted @ 2020-05-30 16:39  DD_XYX  阅读(48)  评论(0编辑  收藏  举报