洛谷 P1606 [USACO07FEB]荷叶塘Lilypad Pond【spfa】

和bzoj同名题不一样!
起点和水点向花费一个荷花能到的第一个点连一条边权为1的有向边,然后跑计数spfa即可

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int N=35,dx[]={-1,-1,1,1,-2,-2,2,2},dy[]={-2,2,-2,2,-1,1,-1,1};
int n,m,a[N][N],id[N][N],tot,h[N*N],cnt,s,t,dis[N*N],vis[N][N],ti;
long long b[N*N];
bool v[N*N];
struct qwe
{
	int ne,to;
}e[500005];
void add(int u,int v)
{//cerr<<u<<" "<<v<<endl;
	cnt++;
	e[cnt].ne=h[u];
	e[cnt].to=v;
	h[u]=cnt;
}
inline bool ok(int x,int y)
{
	return x>=1&&x<=n&&y>=1&&y<=m&&a[x][y]!=2&&vis[x][y]!=ti;
}
void dfs(int u,int x,int y,int f)
{//cerr<<u<<"  "<<x<<" "<<y<<endl;
	vis[x][y]=ti;
	if((a[x][y]==4||a[x][y]==0)&&!f)
	{
		add(u,id[x][y]);
		// add(id[x][y],u);
		return;
	}
	for(int i=0;i<8;i++)
		if(ok(x+dx[i],y+dy[i]))
			dfs(u,x+dx[i],y+dy[i],0);
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
		{
			scanf("%d",&a[i][j]);
			id[i][j]=++tot;
			if(a[i][j]==3)
				s=id[i][j];
			if(a[i][j]==4)
				t=id[i][j];
		}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			if(a[i][j]!=2&&a[i][j]!=1)
				ti++,dfs(id[i][j],i,j,1);
	queue<int>q;
	for(int i=1;i<=tot;i++)
		dis[i]=1e9;
	dis[s]=0;
	b[s]=1;
	v[s]=1;
	q.push(s);
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		v[u]=0;
		for(int i=h[u];i;i=e[i].ne)
		{
			if(dis[e[i].to]>dis[u]+1)
			{
				dis[e[i].to]=dis[u]+1;
				b[e[i].to]=b[u];
				if(!v[e[i].to])
				{
					v[e[i].to]=1;
					q.push(e[i].to);
				}
			}
			else if(dis[e[i].to]==dis[u]+1)
			{
				b[e[i].to]+=b[u];
				if(!v[e[i].to])
				{
					v[e[i].to]=1;
					q.push(e[i].to);
				}
			}
		}
	}
	if(dis[t]==1e9)
		puts("-1");
	else
		printf("%d\n%lld\n",dis[t]-1,b[t]);
	return 0;
}
posted @ 2018-09-01 17:33  lokiii  阅读(160)  评论(0编辑  收藏  举报