题解 P1606 【[USACO07FEB]荷叶塘Lilypad Pond】

顾z

2018-10-14 19:55:22

Solution

# [顾](https://www.luogu.org/blog/RPdreamer/#)[z](https://www.cnblogs.com/-guz/) ~~你没有发现两个字里的blog都不一样嘛~~ qwq 这道题不错啊,表示很考思维. 首先,我们需要知道放多少莲花,如何放. 因此考虑最短路,方案数,我们就考虑最短路计数.(想信大家都会的) 这题的难点在于**如何建边**. > 因为贝西可以跳任何一个位置,(任何一个有水的位置都可以放莲花) > > 所以我们不能单纯地从起点开始向其他点连边,所以我们要从每一个有水的地方开始. > > 由于岩石对答案没有贡献,所以不考虑连边. 多次$dfs$对整个图连边. 既然想到这了,你可能会发现,这是一个二维的最短路,记录状态不太好记录. 因此我们给每一个格子编号,像这样. ![](https://i.loli.net/2018/10/14/5bc32e5e3ec76.png) 当然,还有其他编号方法,这样比较简单罢了. 算某一位置$(x,y)$的编号的话,式子为$idx[x][y]=(x-1)\times m+y$ 这样建边操作就简单多了. 然后后面只需要敲一个裸的最短路和最短路计数问题就好了. **输出添加的荷花的最小的数量的时候要$-1$** 这是因为,这个数量实际上是点权,而我们跑最短路用的是边权. 一个点与两条边相连,所以要$-1$。 ``代码`` ```c++ #include<cstdio> #include<cctype> #include<queue> #include<cstring> #define int long long #define clear(a,b) memset(a,b,sizeof a) #define R register using namespace std; inline void in(int &x) { int f=1;x=0;char s=getchar(); while(!isdigit(s)){if(s=='-')f=-1;s=getchar();} while(isdigit(s)){x=x*10+s-'0';s=getchar();} x*=f; } int n,m,res[35][35],tot,idx[35][35],dis[1008611]; int sx,sy,fx,fy,s,t,head[1008611],to[1008611]; const int ax[]={2,1,-1,-2,2,1,-1,-2}; const int ay[]={1,2,2,1,-1,-2,-2,-1}; bool vis[35][35],inq[1008611]; struct coc{int u,v;}edge[1008611]; inline void add(int x,int y) { edge[++tot].u=head[x]; edge[tot].v=y; head[x]=tot; } void dfs(int id,int x,int y) { if(vis[x][y])return; vis[x][y]=true; for(R int i=0;i<8;i++) { R int nx=x+ax[i],ny=y+ay[i]; if(nx<1 || nx>n || ny>m || ny<1 || vis[nx][ny])continue; //刚开始写成return,尴尬死了 emm if(res[nx][ny]==1)dfs(id,nx,ny); else if(res[nx][ny]!=2) { vis[nx][ny]=true; add(id,idx[nx][ny]); } } } inline void spfa() { queue<int>q; for(R int i=1;i<=n*m;i++)dis[i]=2147483647;dis[s]=0; inq[s]=true;q.push(s);to[s]=1; while(!q.empty()) { int u=q.front();q.pop();inq[u]=false; for(R int i=head[u];i;i=edge[i].u) { if(dis[edge[i].v]>dis[u]+1) { dis[edge[i].v]=dis[u]+1; to[edge[i].v]=to[u]; if(!inq[edge[i].v]) { q.push(edge[i].v); inq[edge[i].v]=true; } } else if(dis[edge[i].v]==dis[u]+1) to[edge[i].v]+=to[u]; } } if(dis[t]<2147483647)printf("%lld\n%lld",dis[t]-1,to[t]); else printf("-1"); } signed main() { in(n),in(m); for(R int i=1;i<=n;i++) for(R int j=1;j<=m;j++) { in(res[i][j]); idx[i][j]=(i-1)*m+j; if(res[i][j]==3)sx=i,sy=j; if(res[i][j]==4)fx=i,fy=j; } for(R int i=1;i<=n;i++) for(R int j=1;j<=m;j++) if(!res[i][j] or res[i][j]==3) clear(vis,0),dfs(idx[i][j],i,j); s=idx[sx][sy];t=idx[fx][fy]; spfa(); } ```