bzoj1698 / P1606 [USACO07FEB]白银莲花池Lilypad Pond
P1606 [USACO07FEB]白银莲花池Lilypad Pond
转化为最短路求解
放置莲花的方法如果直接算会有重复情况。
于是我们可以先预处理和已有莲花之间直接互相可达的点,将它们连边(对,忽略它们)。
于是剩下的就是边权为1的边了。
酱紫我们就成功转化为了边权问题。
蓝后跑跑最短路顺便计个数就解决了。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<queue> 5 using namespace std; 6 #define N 50 7 #define inf 2e9 8 typedef long long ll; 9 struct data{ 10 int d,u; 11 data(){} 12 data(int A,int B): 13 d(A),u(B){} 14 bool operator < (const data &tmp) const{ 15 return d>tmp.d; 16 } 17 };priority_queue <data> h; 18 const int d1[8]={2,2,-2,-2,1,-1,1,-1}; 19 const int d2[8]={-1,1,-1,1,2,2,-2,-2}; 20 int n,m,S,T,id[N][N],e[N][N],d[N*N]; 21 int cnt,hd[N*N],nxt[100009],ed[N*N],poi[100000]; 22 bool vis[N][N]; ll t[N*N]; 23 void adde(int x,int y){ 24 nxt[ed[x]]=++cnt; hd[x]=hd[x]?hd[x]:cnt; 25 ed[x]=cnt; poi[cnt]=y; 26 } 27 void draw(int tt,int x,int y){ 28 vis[x][y]=1; 29 for(int i=0,r1,r2;i<8;++i){ 30 r1=x+d1[i],r2=y+d2[i]; 31 if(r1<1||r1>n||r2<1||r2>m||vis[r1][r2]) continue; 32 if(e[r1][r2]==1) draw(tt,r1,r2); 33 else vis[r1][r2]=1,adde(tt,id[r1][r2]); 34 } 35 } 36 int main(){ 37 scanf("%d%d",&n,&m); 38 for(int i=1,r=0;i<=n;++i) 39 for(int j=1;j<=m;++j){ 40 scanf("%d",&e[i][j]); 41 id[i][j]=++r; d[r]=inf; 42 if(e[i][j]==3) S=r; 43 if(e[i][j]==4) T=r; 44 } 45 for(int i=1;i<=n;++i) 46 for(int j=1;j<=m;++j) 47 if(e[i][j]==0||e[i][j]==3){ 48 memset(vis,0,sizeof(vis)); 49 draw(id[i][j],i,j);//没有莲花:就和其他所有与该点之间只要加一朵莲花就可达的点,连一条边权1的边。 50 } 51 h.push(data(d[S]=0,S)); t[S]=1; 52 while(!h.empty()){ 53 data x=h.top(); h.pop(); 54 if(x.d!=d[x.u]) continue; 55 for(int i=hd[x.u];i;i=nxt[i]){ 56 int to=poi[i]; 57 if(d[to]==d[x.u]+1){ 58 t[to]+=t[x.u]; 59 }else if(d[to]>d[x.u]+1){ 60 d[to]=d[x.u]+1; 61 t[to]=t[x.u]; 62 h.push(data(d[to],to)); 63 } 64 } 65 } 66 if(d[T]==inf) printf("-1"); 67 else printf("%d\n%lld",d[T]-1,t[T]);//减去终点多算的一朵 68 return 0; 69 }