P2937 [USACO09JAN]Laserphones S

题意描述

[USACO09JAN]Laserphones S

学过物理的同学都知道这种镜子是可以把光线旋转 90 度的。

那么显然就是要求添加镜子的最小个数。

貌似题目漏了一句就是题目保证有解的情况。

算法分析

其实可以联想到之前的分层图最短路(不要问我为什么)

建立4层相同的图。层内只能向着某个方向走,因此在可以走的地方建权值为0的边。

层间实现转弯,两两建权值为1的边,表示可以转弯,但有花费。

最后从每一层的起点到每一层的终点跑最短路,统计花费就行了。

代码实现

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#define N 510
#define INF 0x3f3f3f3f
using namespace std;

int n,m,sx,sy,ex,ey,dis[N*N<<2],head[N*N<<2],cnt=0;
int dx[5]={0,1,-1,0,0};
int dy[5]={0,0,0,1,-1};
bool vis[N*N<<2];
char a[N][N];
struct Edge{
	int nxt,to,val;
}ed[N*N<<3];

int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0' || c>'9') f=(c=='-')?-1:1,c=getchar();
	while(c>='0' && c<='9') x=x*10+c-48,c=getchar();
	return x*f;
}

void init(){
	m=read(),n=read();
	char c;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++){
			cin>>c;
			if(c=='C'){
				if(!sx) sx=i,sy=j;
				else ex=i,ey=j;
			}
			a[i][j]=c;
		}
	return;
}

int ID(int t,int x,int y){return (t-1)*n*m+(x-1)*m+y;}

void add(int u,int v,int w){
	ed[++cnt].nxt=head[u];
	ed[cnt].to=v;
	ed[cnt].val=w;
	head[u]=cnt;
	return;
}

void build(){
	for(int t=1;t<=4;t++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=m;j++){
				int fx=i+dx[t];
				int fy=j+dy[t];
				if(fx<1 || fx>n || fy<1 || fy>m || a[fx][fy]=='*' || a[i][j]=='*') continue;
				add(ID(t,i,j),ID(t,fx,fy),0);
			}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++){
			if(a[i][j]=='*') continue;
			for(int u=1;u<=4;u++)
				for(int v=1;v<=4;v++)
					if(u^v) add(ID(u,i,j),ID(v,i,j),1);
		}
	return;
}

int ans=INF;
priority_queue<pair<int,int> >q;

void dij(int s){
	while(!q.empty()) q.pop();
	memset(dis,0x3f,sizeof(dis));
	memset(vis,false,sizeof(vis));
	dis[s]=0;q.push(make_pair(0,s));
	while(!q.empty()){
		int u=q.top().second;q.pop();
		if(vis[u]) continue;
		vis[u]=true;
		for(int i=head[u];i;i=ed[i].nxt){
			int v=ed[i].to,w=ed[i].val;
			if(dis[v]>dis[u]+w){
				dis[v]=dis[u]+w;
				q.push(make_pair(-dis[v],v));
			}
		}
	}
	return;
}

void work(){
	for(int i=1;i<=4;i++){
		dij(ID(i,sx,sy));
		for(int j=1;j<=4;j++)
			ans=min(ans,dis[ID(j,ex,ey)]);
	}
	return;
}

int main(){
	init();
	build();
	work();
	printf("%d\n",ans);
	return 0;
}

完结撒花

猜你喜欢

转载自www.cnblogs.com/lpf-666/p/12735168.html
今日推荐