洛谷 1606

来源:互联网 发布:简单电路 知乎 编辑:程序博客网 时间:2024/05/11 12:33

    这道题与最短路有关应该是比较容易看出的,然后如果没有第二问,我们怎么建图都可以,比如说将莲花与莲花之间建一条边权为0的边,莲花与水建一条边权为1的边,水与水之间建一条边权为1的边,然后跑最短路。这样虽然能够解决第一问,但第二问却无从下手,我们可以感觉到第二问的方案数应该与最短路的方案数有关,但是如果按照上述建图的话,我们很难发现什么关系,因为如果经过的水面相同而经过的莲花不同,会被算作是不同的最短路,而实际上方案却是一样的,我们考虑不同的最短路指的是这条路径上经过的点不完全相同,那如果我们能在跑最短路时只经过水面,这样的最短路方案数一定是题目中要求的方案数,那我们怎么办呢,我们考虑其实莲花与莲花之间的边是没有意义的,它不过是为了保证连通性,同理,除起点和终点外的莲花与水之间的边也是没有意义的,那么我们考虑换一种建图方式,对于每个水,我们将从它能直接跳到或经过若干莲花后能跳到的水连边,将起点和终点与水连边,这样跑最短路,我们发现经过这样建图后最短路上的点除起点和终点是莲花之外,其余的点全是水,这样不同的最短路就对应着经过了不同的水,也就对应着不同的放莲花的方案。

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define maxn 130005int n,m,g[35][35],sx,tx,sy,ty,l,cnt;int pre[maxn],last[maxn],other[maxn];int quex[1000000],quey[1000000],que[1000000];const int dx[9]={0,1,1,2,2,-1,-1,-2,-2};const int dy[9]={0,-2,2,-1,1,-2,2,-1,1};int flag[35][35],dis[1005];bool vis[1005][1005],vist[maxn];long long f[1005];void connect(int x,int y){    l++;    pre[l]=last[x];    last[x]=l;    other[l]=y;    }void bfs(int fx,int fy){    flag[fx][fy]=++cnt;    int h=1,t=0;    for (int i=1;i<=8;i++)     {        int xx=fx+dx[i];        int yy=fy+dy[i];        if (xx<1||xx>n||yy<1||yy>m) continue;        if (flag[xx][yy]==cnt) continue;        flag[xx][yy]=cnt;        if (g[xx][yy]!=2&&g[xx][yy]!=0)         {            t++;            quex[t]=xx;quey[t]=yy;            int id1=(fx-1)*m+fy;            int id2=(xx-1)*m+yy;            if (vis[id1][id2]) continue;            connect(id1,id2);            connect(id2,id1);            vis[id1][id2]=vis[id2][id1]=1;            }        else if (g[xx][yy]==0)             {            int id1=(fx-1)*m+fy;            int id2=(xx-1)*m+yy;            if (vis[id1][id2]) continue;            connect(id1,id2);            connect(id2,id1);            vis[id1][id2]=vis[id2][id1]=1;            }    }    while (h<=t)     {        int x=quex[h],y=quey[h];h++;        for (int i=1;i<=8;i++)         {            int xx=x+dx[i];            int yy=y+dy[i];            if (xx<1||xx>n||yy<1||yy>m) continue;            if (flag[xx][yy]==cnt) continue;            flag[xx][yy]=cnt;            if (g[xx][yy]==0)             {                int id1=(fx-1)*m+fy;                int id2=(xx-1)*m+yy;                if (vis[id1][id2]) continue;                connect(id1,id2);                connect(id2,id1);                vis[id1][id2]=vis[id2][id1]=1;            }            else if (g[xx][yy]!=2&&g[xx][yy]!=0)             {                t++;                quex[t]=xx;quey[t]=yy;                }        }    }}void spfa(void){    memset(dis,53,sizeof dis);    dis[(sx-1)*m+sy]=0;    que[1]=(sx-1)*m+sy;    int h=1,t=1;    while (h<=t)     {        int u=que[h];h++;        vist[u]=0;        for (int p=last[u];p;p=pre[p])         {            int v=other[p];            if (dis[v]>dis[u]+1)             {                dis[v]=dis[u]+1;                    if (!vist[v])                 {                    que[++t]=v;                    vist[v]=1;                    }            }        }    }}void solve(void){    memset(vist,0,sizeof vist);    que[1]=(sx-1)*m+sy;f[que[1]]=1;    int h=1,t=1;    while (h<=t)     {        int u=que[h];h++;        for (int p=last[u];p;p=pre[p])         {            int v=other[p];            if (dis[v]==dis[u]+1)             {                f[v]+=f[u];                if (!vist[v])                 {                    que[++t]=v;                    vist[v]=1;                    }            }        }    }}int main(){    scanf("%d%d",&n,&m);    for (int i=1;i<=n;i++)         for (int j=1;j<=m;j++)         {            scanf("%d",&g[i][j]);            if (g[i][j]==3) {sx=i;sy=j;}            if (g[i][j]==4) {tx=i;ty=j;}        }    bfs(sx,sy);    bfs(tx,ty);    for (int i=1;i<=n;i++)         for (int j=1;j<=m;j++)             if (g[i][j]==0) bfs(i,j);    spfa();    if (dis[(tx-1)*m+ty]>1e7)     {        printf("-1\n");        return 0;    }    printf("%d\n",dis[(tx-1)*m+ty]-1);    solve();    printf("%lld\n",f[(tx-1)*m+ty]);    return 0;    }


0 0
原创粉丝点击