1. 程式人生 > 其它 >高質量好題:ARC118D

高質量好題:ARC118D

儲存一些沒有那麼難的搜尋題目。

小明的遊戲

是通過圖論標籤找到它的,結果它是一個搜尋題?

怎麼說呢,圖論的外表,搜尋的內心。

從圖論的角度來想,那就是對於 \(Dijkstra\) 堆優化部分的進一步優化。由於邊權 \(val\in{0,1}\) ,那麼在堆中只會有兩種 \(dis\) 的結點。考慮用雙端佇列優化這個部分。

從搜尋的角度來想,如果它和國際象棋一樣是交替的(也就是說它每走一步邊權都是1),那麼這就是當年學搜尋的題目了,直接用一個佇列就可以實現廣搜。但問題是它的邊權還有可能是0,那麼我們就需要“更加高階”的佇列,也就是雙端佇列。

兩種思路實現方法一樣,如果擴充套件的一個節點,它不比隊首大,就丟到前面;反之,丟到隊尾。這樣就可以保持佇列內部的單調性,就可以順利完成轉移。

#include<cstdio>
#include<cstring>
#include<deque>
//#define zczc
using namespace std;
const int N=510;
inline void read(int &wh){
    wh=0;int f=1;char w=getchar();
    while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
    while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar(); }
    wh*=f;return;
}
inline bool get(){
	char w=getchar();
	while(w!='#'&&w!='@')w=getchar();
	return w=='#';
}

int m,n,fx,fy,ex,ey;
bool a[N][N];
bool entering(){
	read(m);read(n);
	if(m==0&&n==0)return false;
	for(int i=1;i<=m;i++){
		for(int j=1;j<=n;j++){
			a[i][j]=get();
		}
	}
	read(fx);read(fy);read(ex);read(ey);
	fx++,fy++,ex++,ey++;
	return true;
}
int an[N][N],f[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
bool vis[N][N];
struct node{
	int x,y,dis;
};
deque<node>q;
inline void add(node wh){
	if(q.empty()||wh.dis<=q.front().dis)q.push_front(wh);
	else q.push_back(wh);return;
}
inline bool check(int x,int y){
	return x<1||y<1||x>m||y>n;
}
void solve(){
	memset(an,0x3f,sizeof(an));
	memset(vis,false,sizeof(vis));
	while(!q.empty())q.pop_front();
	an[fx][fy]=0;
	add((node){fx,fy,0});
	while(!q.empty()){
		node now=q.front();q.pop_front();
		int nx=now.x,ny=now.y,nd=now.dis;
		if(nx==ex&&ny==ey){
			printf("%d\n",now.dis);
			return;
		}
		if(vis[nx][ny])continue;vis[nx][ny]=true;
		for(int i=0;i<4;i++){
			int rx=nx+f[i][0],ry=ny+f[i][1];
			if(check(rx,ry))continue;
			if(an[nx][ny]+(a[nx][ny]^a[rx][ry])<an[rx][ry]){
				an[rx][ry]=an[nx][ny]+(a[nx][ny]^a[rx][ry]);
				add((node){rx,ry,an[rx][ry]});
			}
		}
	}
	return;
}

signed main(){
	
	#ifdef zczc
	freopen("in.txt","r",stdin);
	#endif
	
	while(entering())solve();
	
	return 0;
}
一如既往,萬事勝意