校内测试-城堡

 

题目 

 

测试得分:  100

 

主要算法 :  最短路-dijkstra,矩阵动规

 

题干:

  矩阵中求左上角的点到右下角的点的距离,不能从下往上走

 

分析:

  方案1(动规)
  初步判定算法

    对于这题,只能从上往下行走,对于到达每一个点的最优值,一定是从最上方下来的最优值,与左右两边最优值的比较,初步确定算法动态规划

  分析初步算法

     对于从两边来的最优值,只有左边目前是一路DP过来的最优值,而对于右边则是一个未知的,所以要进行两步DP,想从左边扫一遍左值,在从右扫一遍右值,上方,左右三者取一个min则是到这个点的最小花

  方案2(最短路)
  初步判定算法

    典型的最短路问题

  分析初步算法    

    将每一个节点,按照从上到下,从左到右的顺序编号,点数为N*M

     建立到右边一个点,权值为右边那个点的权值的边,再建立到左边一个点,权值为左边那个点的权值的边,再建立到下边一个点,权值为下边那个点的权值的边。边数为3*M*N

     跑一个最短路dijkstra,时间复杂度O(n*log(m)),对于这道题时间上是跑不过去的,可以得部分分

  

 代码

#include<queue>
#include<stdio.h>
#include<stdlib.h>
#define INF 2147483647
#define FORa(i,s,e) for(int i=s;i<=e;i++)
#define FORs(i,s,e) for(int i=s;i>=e;i--)
#define gc pa==pb&&(pb=(pa=buf)+fread(buf,1,100000,stdin),pa==pb)?EOF:*pa++
#define File(name) freopen(name".in","r",stdin),freopen(name".out","w",stdout);

using namespace std;
static char buf[1000000],*pa=buf,*pb=buf;
inline int read();

const int M=1000,N=1000;
struct Node{
    int next,to,dis;
}edge[M*N*4];
bool bz[M*N];
int a[N+1][M+1]; 
int n,m,star,end,dis[M*N],head[M*N],num_edge,fdis[N+1][M+1];
inline int min(int fa,int fb){return fa<fb?fa:fb;}
void Add_edge(int from,int to,int d)
{
    num_edge++,edge[num_edge]=(Node){head[from],to,d},head[from]=num_edge;
}
struct Que{
    int u,dis;
    bool operator < (const Que &q) const{ 
        return dis>q.dis;
    } 
}q;
priority_queue<Que> que;
void Solve()
{
    FORa(i,1,n) FORa(j,1,m) a[i][j]=read();
    FORa(i,1,n) FORa(j,2,m) Add_edge((i-1)*m+j-1,(i-1)*m+j,a[i][j]),Add_edge((i-1)*m+j,(i-1)*m+j-1,a[i][j-1]);
    FORa(j,1,m) FORa(i,2,n) Add_edge((i-2)*m+j,(i-1)*m+j,a[i][j]);
    FORa(i,1,m*n) dis[i]=INF;
    star=1,dis[star]=0,que.push((Que){star,0});
    while(!que.empty())
    {
        q=que.top(),que.pop();
        if(bz[q.u]) continue;
        bz[q.u]=1;
        for(int i=head[q.u];i;i=edge[i].next)
        {
            if(dis[edge[i].to]>dis[q.u]+edge[i].dis)
            {
                dis[edge[i].to]=dis[q.u]+edge[i].dis;
                if(!bz[edge[i].to]) que.push((Que){edge[i].to,dis[edge[i].to]});
            }
        }
    }
    printf("%d",dis[m*n]);
}
void Solve2()
{
    FORa(i,1,n) FORa(j,1,m)    a[i][j]=read();
    FORa(i,1,m)  a[1][i]=a[1][i-1]+a[1][i],fdis[1][i]=a[1][i];
    FORa(i,2,n)
    {
        FORa(j,1,m)
        {
            if(j>1) fdis[i][j]=a[i][j]+min(fdis[i-1][j],fdis[i][j-1]);
            else fdis[i][j]=a[i][j]+fdis[i-1][j];
        }
        FORs(j,m,1)
        {
            if(j<=m-1) fdis[i][j]=min(fdis[i][j],a[i][j]+min(fdis[i-1][j],fdis[i][j+1]));
            else fdis[i][j]=min(fdis[i][j],a[i][j]+fdis[i-1][j]);
        }
    }
    printf("%d",fdis[n][m]);
}
int main()
{
    File("castle");
    n=read(),m=read();
    if(n*m<=100) Solve();
    else Solve2();
    return 0;
}
inline int read()
{
    register int x(0);register int f(1);register char c(gc);
    while(c<'0'||c>'9') f=c=='-'?-1:1,c=gc;
    while(c>='0'&&c<='9') x=(x<<1)+ (x<<3)+(c^48),c=gc;
    return x*f;
}

 

 

 

 

转载于:https://www.cnblogs.com/SeanOcean/p/11618057.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值