洛谷 1606

Posted TSOI_Vergil

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷 1606相关的知识,希望对你有一定的参考价值。

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

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 130005
int 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;    


以上是关于洛谷 1606的主要内容,如果未能解决你的问题,请参考以下文章

洛谷——P2678 跳石头

洛谷——P2296 寻找道路

洛谷 P2296 寻找道路

洛谷 P2296 寻找到路

AC日记——寻找道路 洛谷 P2296

[NOIP2015提高&洛谷P2678]跳石头 题解(二分答案)