荷叶塘(建图+最短路)
为了让奶牛们娱乐和锻炼,农夫约翰建造了一个美丽的池塘。这个长方形的池子被分成了M行N列个方格(1≤M,N≤30)。一些格子是坚固得令人惊讶的莲花,还有一些格子是岩石,其余的只是美丽、纯净、湛蓝的水。
贝西正在练习芭蕾舞,她站在一朵莲花上,想跳到另一朵莲花上去,她只能从一朵莲花跳到另一朵莲花上,既不能跳到水里,也不能跳到岩石上。
贝西的舞步很像象棋中的马步:每次总是先横向移动一格,再纵向移动两格,或先纵向移动两格,再横向移动一格。最多时,贝西会有八个移动方向可供选择。
约翰一直在观看贝西的芭蕾练习,发现她有时候不能跳到终点,因为中间缺了一些荷叶。于是他想要添加几朵莲花来帮助贝西完成任务。一贯节俭的约翰只想添加最少数量的莲花。当然,莲花不能放在石头上。
请帮助约翰确定必须要添加的莲花的最少数量,以及有多少种放置这些莲花的方法。
Solution
我太傻了,
一开始就直接枚举周围点,有荷花连0遍,没有就连1边,再最短路计数一下。
首先,这个图就有问题,问的是摆放方案,我写的是路径方案。
而且这样会出现0环,spfa炸了。
所以我们采用dfs建图的方式,从一个点一直走知道碰到水,然后连一条1边就行了。
Code
#include<iostream> #include<cstdio> #include<queue> #include<cstring> #define N 32 using namespace std; queue<int>q; int dis[N*N],n,m,a[N][N],id[N][N],tot,s,t,head[N*N],ji[N][N],num; long long dp[N*N]; bool vis[N*N]; const int dx[8]={1,-1,-1,1,2,-2,2,-2}; const int dy[8]={2,2,-2,-2,1,1,-1,-1}; struct zzh{ int n,to; }e[200002]; inline void add(int u,int v){ e[++tot].n=head[u]; e[tot].to=v; head[u]=tot; } void dfs(int pos,int i,int j,int tag){ ji[i][j]=num; if(!tag&&(a[i][j]==0||a[i][j]==4)){ add(pos,id[i][j]); return; } for(int k=0;k<8;++k){ int x=i+dx[k],y=j+dy[k]; if(x<1||y<1||x>n||y>m||a[x][y]==2||ji[x][y]==num)continue; dfs(pos,x,y,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]!=4)num++,dfs(id[i][j],i,j,1); memset(dis,0x3f,sizeof(dis)); q.push(s);dis[s]=0;dp[s]=1; while(!q.empty()){ int u=q.front();q.pop();vis[u]=0; for(int i=head[u];i;i=e[i].n){ int v=e[i].to; if(dis[v]>dis[u]+1){ dis[v]=dis[u]+1; dp[v]=dp[u]; if(!vis[v]){ vis[v]=1; q.push(v); } } else if(dis[v]==dis[u]+1){ dp[v]+=dp[u]; if(!vis[v]){ vis[v]=1; q.push(v); } } } } if(dis[t]==0x3f3f3f3f)cout<<-1; else cout<<dis[t]-1<<endl<<dp[t]; return 0; }