zoukankan      html  css  js  c++  java
  • 荷叶塘(建图+最短路)

    为了让奶牛们娱乐和锻炼,农夫约翰建造了一个美丽的池塘。这个长方形的池子被分成了M行N列个方格(1≤M,N≤30)。一些格子是坚固得令人惊讶的莲花,还有一些格子是岩石,其余的只是美丽、纯净、湛蓝的水。

    贝西正在练习芭蕾舞,她站在一朵莲花上,想跳到另一朵莲花上去,她只能从一朵莲花跳到另一朵莲花上,既不能跳到水里,也不能跳到岩石上。

    贝西的舞步很像象棋中的马步:每次总是先横向移动一格,再纵向移动两格,或先纵向移动两格,再横向移动一格。最多时,贝西会有八个移动方向可供选择。

    约翰一直在观看贝西的芭蕾练习,发现她有时候不能跳到终点,因为中间缺了一些荷叶。于是他想要添加几朵莲花来帮助贝西完成任务。一贯节俭的约翰只想添加最少数量的莲花。当然,莲花不能放在石头上。

    请帮助约翰确定必须要添加的莲花的最少数量,以及有多少种放置这些莲花的方法。

    Solution

    我太傻了,

    一开始就直接枚举周围点,有荷花连0遍,没有就连1边,再最短路计数一下。

    首先,这个图就有问题,问的是摆放方案,我写的是路径方案。

    而且这样会出现0环,spfa炸了。

    所以我们采用dfs建图的方式,从一个点一直走知道碰到水,然后连一条1边就行了。

    Code

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #define N 32
    using namespace std;
    queue<int>q;
    int dis[N*N],n,m,a[N][N],id[N][N],tot,s,t,head[N*N],ji[N][N],num;
    long long dp[N*N];
    bool vis[N*N];
    const int dx[8]={1,-1,-1,1,2,-2,2,-2};
    const int dy[8]={2,2,-2,-2,1,1,-1,-1};
    struct zzh{
        int n,to;
    }e[200002];
    inline void add(int u,int v){
        e[++tot].n=head[u];
        e[tot].to=v;
        head[u]=tot;
    }
    void dfs(int pos,int i,int j,int tag){
        ji[i][j]=num;
         if(!tag&&(a[i][j]==0||a[i][j]==4)){
             add(pos,id[i][j]);
             return;
         }
         for(int k=0;k<8;++k){
                    int x=i+dx[k],y=j+dy[k];
                    if(x<1||y<1||x>n||y>m||a[x][y]==2||ji[x][y]==num)continue;
                  dfs(pos,x,y,0);
             }
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i)
          for(int j=1;j<=m;++j){
              scanf("%d",&a[i][j]);
              id[i][j]=++tot;
             if(a[i][j]==3)s=id[i][j];
             if(a[i][j]==4)t=id[i][j]; 
          }
        for(int i=1;i<=n;++i)
          for(int j=1;j<=m;++j)
            if(a[i][j]!=2&&a[i][j]!=4)num++,dfs(id[i][j],i,j,1);
        memset(dis,0x3f,sizeof(dis));
        q.push(s);dis[s]=0;dp[s]=1;
        while(!q.empty()){
            int u=q.front();q.pop();vis[u]=0;
            for(int i=head[u];i;i=e[i].n){
                int v=e[i].to;
                if(dis[v]>dis[u]+1){
                    dis[v]=dis[u]+1;
                    dp[v]=dp[u];
                    if(!vis[v]){
                        vis[v]=1;
                        q.push(v);
                    }
                }
                else if(dis[v]==dis[u]+1){
                  dp[v]+=dp[u];
                  if(!vis[v]){
                      vis[v]=1;
                      q.push(v);
                  }
                }
            }
        }
        if(dis[t]==0x3f3f3f3f)cout<<-1;
        else cout<<dis[t]-1<<endl<<dp[t];
        return 0;
    }
  • 相关阅读:
    15 反转链表
    八大排序算法总结(2)
    八大排序算法总结(1)
    22从上往下打印二叉树
    19顺时针打印矩阵
    20包含min函数的栈
    SpringMVC-Mybatis整合和注解开发
    优雅的代码之选择不同支付方式
    利用freemarker+SAX解析xml的方式对excel文件字段校验
    pl/sql编程语言
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/9723907.html
Copyright © 2011-2022 走看看