luoguP1606 [USACO07FEB]荷葉塘Lilypad Pond--最短路計數
阿新 • • 發佈:2018-12-11
題目大意:新增最少石頭的方案數。
一種樸素的想法是是每個節點向外建邊,是荷花建0邊,新增建1邊,然後跑最短路計數,這樣只能得部分分。為什麼呢?比如可以多個荷花節點向同一個水節點建邊,實際是一種放置石頭得方案,但這樣就會統計成多種。 因此正確得建圖方法是一個荷花聯通塊,新增一個石頭可以到達哪裡。,然後再統計最短路條數就是不同得方案數了。
建圖抄了dfs的,又寫了個bfs的。原理是一樣的。
參考程式碼:
#include<cmath> #include<queue> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<iostream> using namespace std; typedef long long LL; const int N=31,inf=0x3f3f3f3f; const int fx[8][2]= {2,-1,2,1,-2,-1,-2,1,1,2,-1,2,1,-2,-1,-2}; struct node { int to,next; } e[500010]; int cnt,head[N*N]; void add(int u,int v) { e[++cnt].to=v; e[cnt].next=head[u]; head[u]=cnt; } int mp[N][N],dis[N*N],p[N][N],inq[N*N],n,m; LL f[N*N]; bool vis[N][N]; void dfs(int po,int x,int y) {//dfs建邊。 vis[x][y]=1; for(int i=0; i<8; i++) { int dx=x+fx[i][0],dy=y+fx[i][1]; if(dx<1 || dy<1 || dx>n || dy>m || vis[dx][dy])continue; if(mp[dx][dy]==1)dfs(po,dx,dy);//這個點是花,直接跳過去。 else vis[dx][dy]=1,add(po,p[dx][dy]);//這個點不是花,加一個花 } } void bfs(int po,int x,int y) { //bfs建邊,處理荷葉聯通塊,荷葉直接進佇列,向水或終點建邊。 queue<int>qx,qy; qx.push(x),qy.push(y); vis[x][y]=1;//進過佇列不再進佇列 while(!qx.empty()) { int x=qx.front(),y=qy.front(); qx.pop(),qy.pop(); for(int i=0; i<8; i++) { int dx=x+fx[i][0],dy=y+fx[i][1]; if(dx<1 || dy<1 || dx>n || dy>m || vis[dx][dy])continue; vis[dx][dy]=1; if(mp[dx][dy]==1)qx.push(dx),qy.push(dy);// else if(mp[dx][dy]!=2)add(po,p[dx][dy]); } } } queue<int>q; int main() { int i,j,x,y,k,st,ed; cin>>n>>m; for(i=1; i<=n; i++) for(j=1; j<=m; j++)p[i][j]=(i-1)*m+j; for(i=1; i<=n; i++) for(j=1; j<=m; j++) { cin>>mp[i][j]; if(mp[i][j]==3)st=p[i][j]; if(mp[i][j]==4)ed=p[i][j]; } for(i=1; i<=n; i++) for(j=1; j<=m; j++) if(mp[i][j]!=2) { memset(vis,0,sizeof(vis)); bfs(p[i][j],i,j); } memset(dis,127,sizeof(dis)); memset(inq,0,sizeof(inq)); dis[st]=0,inq[st]=1; f[st]=1; q.push(st); while(!q.empty()) { int v,u=q.front(); q.pop(); inq[u]=0; for(int i=head[u]; i; i=e[i].next) { v=e[i].to; if(dis[v]>dis[u]+1) { dis[v]=dis[u]+1,f[v]=f[u]; if(!inq[v]) { inq[v]=1; q.push(v); } } else if(dis[v]==dis[u]+1) f[v]+=f[u]; } } if(dis[ed]<inf)printf("%d\n%lld\n",dis[ed]-1,f[ed]); else printf("-1\n"); return 0; }