题目:
为了让奶牛们娱乐和锻炼,农夫约翰建造了一个美丽的池塘。这个长方形的池子被分成了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。
瞄了一脸数据,再看统计方案数,是他准没错!!
就是模版加上统计数而已。
统计数就是每次如果找到和他同样的;路径就在原来基础上+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。
如果你懒,用了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();
}