[P1606] Baiyin Lian Hua Chi Luo Gu [shortest]

Subject to the effect:

Topic link: https://www.luogu.org/problemnew/show/P1606
a n × m n\times m of the grid points may be some step, not to step on other points. Every time a person will walk around "day" type move, seeking at least a few points you want to change can step into the point can make this person from S S arrived T T point, and the number of programs.


Ideas:

The first question can immediately think of b f s bfs , but the second question apparentlythe shortest count, the first consideration is also asked to do the most short-circuited.
The simplest idea is that every point Wangwaimian eight Japanese fonts even point edge, right edge if the point is not step 1, otherwise the right side is zero. But some duplicate count will be less so when the shortest point counts, leading to wrong answer.
So consider the right side to side 0 removed, leaving only the right side is the side 1. So consider using d f s dfs building side. For each point, with d f s dfs to find a point with all of its distance, and even to the edge.
The next step is setshortest templatesandshortest template countup.


Code:

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#define mp make_pair
using namespace std;
typedef long long ll;

const int N=40,M=500010;
const int dx[]={0,-2,-1,1,2,-2,-1,1,2};
const int dy[]={0,-1,-2,2,1,1,2,-2,-1};
int n,m,S,T,tot,map[N][N],head[N*N],dis[N*N];
ll cnt[N*N];
bool vis[N*N];

struct edge
{
	int next,to,dis;
}e[M]; 

int C(int x,int y)
{
	return (x-1)*m+y;
}

void add(int from,int to,int dis)
{
	e[++tot].to=to;
	e[tot].dis=dis;
	e[tot].next=head[from];
	head[from]=tot;
}

void dfs(int root,int x,int y)
{
	if (vis[C(x,y)]) return;
	vis[C(x,y)]=1;
	for (int i=1;i<=8;i++)
	{
		int xx=x+dx[i],yy=y+dy[i];
		if (xx>=1 && xx<=n && yy>=1 && yy<=m && !vis[C(xx,yy)])
		{
			if (map[xx][yy]==1) dfs(root,xx,yy);
			else if (map[xx][yy]!=2)
			{
				add(root,C(xx,yy),1);
				vis[C(xx,yy)]=1;
			}
		}
	}
}

void dij()
{
	memset(dis,0x3f3f3f3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	priority_queue<pair<int,int> > q;
    q.push(make_pair(0,S));
    dis[S]=0;
    cnt[S]=1;
    while (q.size())
    {
        int u=q.top().second;
        q.pop();
        if (vis[u]) continue;
        vis[u]=1;
        for (int i=head[u];~i;i=e[i].next)
        {
            int v=e[i].to;
            if (dis[v]>dis[u]+e[i].dis)
            {
                dis[v]=dis[u]+e[i].dis;
                cnt[v]=cnt[u];
                q.push(make_pair(-dis[v],v));
            }
            else if (dis[v]==dis[u]+e[i].dis)
            	cnt[v]+=cnt[u];
        }
    }
}

int main()
{
	freopen("data.in","r",stdin);
	memset(head,-1,sizeof(head));
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++)
		for (int j=1;j<=m;j++)
		{
			scanf("%d",&map[i][j]);
			if (map[i][j]==3) S=C(i,j);
			if (map[i][j]==4) T=C(i,j);
		}
	for (int i=1;i<=n;i++)
		for (int j=1;j<=m;j++)
			if (map[i][j]!=1&&map[i][j]!=2)
			{
				memset(vis,0,sizeof(vis));
				dfs(C(i,j),i,j);
			}
	dij();
	if (dis[T]<1e9) cout<<dis[T]-1<<endl<<cnt[T]<<endl;
		else printf("-1\n");
	return 0;
}

Guess you like

Origin blog.csdn.net/SSL_ZYC/article/details/93378838