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 }
View Code

 

posted @ 2018-12-03 13:47  kafuuchino  阅读(210)  评论(0编辑  收藏  举报