P1606 [USACO07FEB]白银莲花池Lilypad Pond

题目:

为了让奶牛们娱乐和锻炼,农夫约翰建造了一个美丽的池塘。这个长方形的池子被分成了M行N列个方格(1≤M,N≤30)。一些格子是坚固得令人惊讶的莲花,还有一些格子是岩石,其余的只是美丽、纯净、湛蓝的水。

贝西正在练习芭蕾舞,她站在一朵莲花上,想跳到另一朵莲花上去,她只能从一朵莲花跳到另一朵莲花上,既不能跳到水里,也不能跳到岩石上。

贝西的舞步很像象棋中的马步:每次总是先横向移动一格,再纵向移动两格,或先纵向移动两格,再横向移动一格。最多时,贝西会有八个移动方向可供选择。

约翰一直在观看贝西的芭蕾练习,发现她有时候不能跳到终点,因为中间缺了一些荷叶。于是他想要添加几朵莲花来帮助贝西完成任务。一贯节俭的约翰只想添加最少数量的莲花。当然,莲花不能放在石头上。

请帮助约翰确定必须要添加的莲花的最少数量,以及有多少种放置这些莲花的方法。

 

呵呵,也许看到题目你就懵逼了吧,是的,一开始我也有点懵逼。他这放的什么东西啊?放莲叶?方案数?

后来慢慢斯理了一下题目,发现好像也不难,洛谷评分给到了紫题。

一开始吓出一身汗,后来打完发现迷迷糊糊接近正解,然后就检查了一下,样例过了。

然后交上去,72分WDF,想都没想到,然后去看错的点。

看到一个10位数,马上开了long long,然后错一个点。

一脸懵再去看,发现-1没输出来,改完就对了。

然后觉得这道题弱爆了。

现在我给大家讲一讲思路。

首先:一只牛去跳马步,所以方向不能错。


int dx[8]={2,2,-2,-2,1,-1,1,-1};
int dy[8]={-1,1,-1,1,2,2,-2,-2};

然后我们自然就想到,先确定起点和终点,设这个图每个点都是前一个点+1

那么就变成了如下图

1 2 3 4 5

6 7 8 9 10

11 12 13 14 15

然后我们每读入一个数,判断他是否为起点或终点,如果是就bz

signed main()
{
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++)
	{
        for(int j=1;j<=m;j++)
        {
            pp[i][j]=(i-1)*m+j;
        }
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			scanf("%lld",&c[i][j]);
			if(c[i][j]==3) st=pp[i][j];
			if(c[i][j]==4) ed=pp[i][j];
		}
	}

然后只有水和起点是可以造莲叶的,一定要记住,起点可能没有莲叶!!!

每找到一次我们就建边跑最短路去。

以下是搜索过程

for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(c[i][j]==0||c[i][j]==3)
			{
				memset(v,0,sizeof(v));
				dfs(pp[i][j],i,j);
			}
		}
	}
void dfs(int ans,int x,int y)
{
	v[x][y]=1;
	for(int i=0;i<=7;i++)
	{
		int xx=x+dx[i],yy=y+dy[i];
		if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&v[xx][yy]==0)
		{
			if(c[xx][yy]==1) dfs(ans,xx,yy);
			else
			{
				v[xx][yy]=1;
				ins(ans,pp[xx][yy]);
			}
		}
	}
}

ans表示当前他是第几个格子,然后就建一条以他为终点的边,边权自然为当前下一个点。

然后我们就可以愉快的跑spfa。

为什么会想到SPFA,他不是死了吗?

瞄了一脸数据,再看统计方案数,是他准没错!!

就是模版加上统计数而已。

统计数就是每次如果找到和他同样的;路径就在原来基础上+1;

否则继承,注意不是0!!

代码如下:

void spfa()
{
	for(int i=1;i<=n;i++) d[i]=999999999;
	d[st]=0;
	memset(vv,false,sizeof(vv));vv[st]=true;
	ans[st]=1;
	queueq;
	q.push(st);
	while(!q.empty())
	{
		int x=q.front();q.pop();vv[x]=false;
		for(int k=last[x];k;k=a[k].next)
		{
			int y=a[k].y;
			if(d[y]>d[x]+1)
			{
				ans[y]=ans[x];
				d[y]=d[x]+1;
				if(vv[y]==false)
				{
					vv[y]=true;
					q.push(y);
				}
			}
			else if(d[y]==d[x]+1) ans[y]+=ans[x];
		}
	}
	if(d[ed]==999999999) printf("-1\n");
	else printf("%lld\n%lld\n",d[ed]-1,ans[ed]);
}

记住这里有一个坑点,终点的莲叶是不用放的,但我们在程序过程中加上了1,所以在这里要把它减掉1。

然后就是注意如果一直都输不出来也就是大于999999999的话要输出-1。

十年OI一场空,不开 LONG LONG见祖宗。

如果你懒,用了define int long long

请将主程序弄成SIGNED MAIN()

 

听某位大佬的要求博客结束后要把所有的代码放一遍

那蒟蒻就听着吧!!

#include
#include
#include
#define int long long
using namespace std;
struct node
{
	int x,y,next;
}a[210000];
int len=0,ans[210000],v[210][210],last[210000],p[210][210],n,m,st,ed;
int d[210000],c[210][210],pp[210][210];
bool vv[210000];
int dx[8]={2,2,-2,-2,1,-1,1,-1};
int dy[8]={-1,1,-1,1,2,2,-2,-2};
void ins(int x,int y)
{
	len++;
	a[len].x=x;a[len].y=y;
	a[len].next=last[x];last[x]=len;
}
void dfs(int ans,int x,int y)
{
	v[x][y]=1;
	for(int i=0;i<=7;i++)
	{
		int xx=x+dx[i],yy=y+dy[i];
		if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&v[xx][yy]==0)
		{
			if(c[xx][yy]==1) dfs(ans,xx,yy);
			else
			{
				v[xx][yy]=1;
				ins(ans,pp[xx][yy]);
			}
		}
	}
}
void spfa()
{
	for(int i=1;i<=n;i++) d[i]=999999999;
	d[st]=0;
	memset(vv,false,sizeof(vv));vv[st]=true;
	ans[st]=1;
	queueq;
	q.push(st);
	while(!q.empty())
	{
		int x=q.front();q.pop();vv[x]=false;
		for(int k=last[x];k;k=a[k].next)
		{
			int y=a[k].y;
			if(d[y]>d[x]+1)
			{
				ans[y]=ans[x];
				d[y]=d[x]+1;
				if(vv[y]==false)
				{
					vv[y]=true;
					q.push(y);
				}
			}
			else if(d[y]==d[x]+1) ans[y]+=ans[x];
		}
	}
	if(d[ed]==999999999) printf("-1\n");
	else printf("%lld\n%lld\n",d[ed]-1,ans[ed]);
}
signed main()
{
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++)
	{
        for(int j=1;j<=m;j++)
        {
            pp[i][j]=(i-1)*m+j;
        }
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			scanf("%lld",&c[i][j]);
			if(c[i][j]==3) st=pp[i][j];
			if(c[i][j]==4) ed=pp[i][j];
		}
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(c[i][j]==0||c[i][j]==3)
			{
				memset(v,0,sizeof(v));
				dfs(pp[i][j],i,j);
			}
		}
	}
	spfa();
}

结束了,就是这么一道紫题

BY ZZJ 2019.1.26 10:08

你可能感兴趣的:(P1606 [USACO07FEB]白银莲花池Lilypad Pond)