POJ 3271 Lilypad Pond 最短路径的转化

时空隧道


题意(原谅我懒癌晚期)


分析:
第一次看错题目了…以为是路径总数…直接写spfa…后来发现是0的位置不同才叫方案不同…额…2333333333333
现在考虑我们所求的是0的位置不同的方案总数…
因为1的存在…我们无法直接得到当前路径上0的位置…所以说要想一种机智的办法来排除1的干扰…
第一想法是把1去掉…但是这样会导致一些合法的路径被断开…那怎么办…那就把因为去掉1而断开的边强行加上去一条权值为1的边…
所以我们就可以通过bfs找到每个0点和起点的能够花费1个代价到达的点…从而得到一张新的图,然后再这张图上跑最短路统计方案数即可…
但是在处理方案数目的时候我犯了一个zz的错误…我选择了dijkstra…其实可以统计…但是我妄想用一个”优美“的算法(一遍求出来)…然后就挂了…


代码如下:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#define inf 0x3f3f3f3f
//by NeighThorn
using namespace std;
const int maxn=900+5,maxm=810000+5;
int n,m,mp[35][35],hd[maxn],to[maxm],vis[35][35],vi[maxn],nxt[maxm],cnt,stx,sty,enx,eny,mv[8][2]={1,2,-1,2,-1,-2,1,-2,2,1,-2,1,-2,-1,2,-1},dis[maxn];
long long num[maxn];
struct M{
    int v,d;
    M(int a=0,int b=0){
        v=a,b=d;
    }
    friend bool operator < (M x,M y){
        return x.d>y.d;
    }
};
struct lala{
    int x,y,step;
    lala(int a=0,int b=0,int c=0){
        x=a,y=b,step=c;
    }
};
inline void add(int x,int y){
    to[cnt]=y;
    nxt[cnt]=hd[x];
    hd[x]=cnt++;
}
inline void bfs(int X,int Y){
    memset(vis,0,sizeof(vis));
    queue<lala> q;
    q.push(lala(X,Y,0)),vis[X][Y]=1;
    while(!q.empty()){
        int x=q.front().x,y=q.front().y,step=q.front().step;
        q.pop();
        for(int i=0;i<=7;i++){
            int xx=x+mv[i][0],yy=y+mv[i][1];
            if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&!vis[xx][yy]&&mp[xx][yy]!=2&&mp[xx][yy]!=3){
                if(mp[xx][yy]==4&&step==0)
                    add((X-1)*m+Y,(xx-1)*m+yy),vis[xx][yy]=1;
                else if(mp[xx][yy]==1&&step==0)
                    add((X-1)*m+Y,(xx-1)*m+yy),vis[xx][yy]=1;
                else if(mp[xx][yy]==0&&step==0)
                    q.push(lala(xx,yy,step)),vis[xx][yy]=1;
            }
        }
    }
}
inline void findsmallestlength(void){
    queue<int> q;memset(dis,inf,sizeof(dis));memset(num,0,sizeof(num));memset(vi,0,sizeof(vi));
    q.push((stx-1)*m+sty),vi[(stx-1)*m+sty]=1,dis[(stx-1)*m+sty]=-1,num[(stx-1)*m+sty]=1;
    while(!q.empty()){
        int top=q.front();q.pop();vi[top]=0;
        for(int i=hd[top];i!=-1;i=nxt[i]){
            if(dis[to[i]]>dis[top]+1){
                dis[to[i]]=dis[top]+1,num[to[i]]=num[top];
                if(!vi[to[i]])
                    q.push(to[i]),vi[to[i]]=1;
            }
            else if(dis[to[i]]==dis[top]+1){
                num[to[i]]+=num[top];
                if(!vi[to[i]])
                    q.push(to[i]),vi[to[i]]=1;
            }
        }
    }
}
signed main(void){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
        scanf("%d",&mp[i][j]);
        if(mp[i][j]==3)
            stx=i,sty=j;
        else if(mp[i][j]==4)
            enx=i,eny=j;
        else if(mp[i][j]!=2)
            mp[i][j]^=1;
    }cnt=0;
    memset(hd,-1,sizeof(hd));
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)   
            if(mp[i][j]==1||mp[i][j]==3)
                bfs(i,j);
    findsmallestlength();
    if(dis[(enx-1)*m+eny]==inf)
        puts("-1");
    else
        cout<<dis[(enx-1)*m+eny]<<endl<<num[(enx-1)*m+eny]<<endl;
    return 0;
}

by >_< NeighThorn

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值