51nod 1459 迷宫游戏

基准时间限制:1 秒 空间限制:131072 KB 分值: 0  难度:基础题
 收藏
 关注
你来到一个迷宫前。该迷宫由若干个房间组成,每个房间都有一个得分,第一次进入这个房间,你就可以得到这个分数。还有若干双向道路连结这些房间,你沿着这些道路从一个房间走到另外一个房间需要一些时间。游戏规定了你的起点和终点房间,你首要目标是从起点尽快到达终点,在满足首要目标的前提下,使得你的得分总和尽可能大。现在问题来了,给定房间、道路、分数、起点和终点等全部信息,你能计算在尽快离开迷宫的前提下,你的最大得分是多少么?
Input
第一行4个整数n (<=500), m, start, end。n表示房间的个数,房间编号从0到(n - 1),m表示道路数,任意两个房间之间最多只有一条道路,start和end表示起点和终点房间的编号。
第二行包含n个空格分隔的正整数(不超过600),表示进入每个房间你的得分。
再接下来m行,每行3个空格分隔的整数x, y, z (0<z<=200)表示道路,表示从房间x到房间y(双向)的道路,注意,最多只有一条道路连结两个房间, 你需要的时间为z。
输入保证从start到end至少有一条路径。
Output
一行,两个空格分隔的整数,第一个表示你最少需要的时间,第二个表示你在最少时间前提下可以获得的最大得分。
Input示例
3 2 0 2
1 2 3
0 1 10
1 2 11
Output示例
21 6

首先我没用迪杰斯特拉算法做  广搜暴力的 - -


广搜中的队列和深搜的区别就是一个单路如何没有回路的一个标记  这时候需要用一个空间模拟一个深搜递归的空间变化   保证广搜队列的情况下也可以找到哪个点是走过的  把那一条路标记出来,之后就可以避免走回路  之后最重要的是  每次的边权值变小的时候,需要把当前的价值也变小

下面代码是比较完善的

#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <queue>
#include <map>
#include <cstring>
#include <iomanip>
#include <cstring>
using namespace std;
const long long mod=10000;
long long tag[505][505];//邻接矩阵
long long dp[15005];//权值更新
long long dpp[15005];//价值更新
long long d[15005];//时间记录
long long p[15005];//位置记录
long long v[15005];//价值记录
long long s[15005];//房间价值记录
int dq[10005][505];//路径记录
int main()
{
    long long n,m;
    while(cin>>n>>m)
    {
        long long a,b;
        cin>>a>>b;
        memset(tag,0,sizeof(tag));
        memset(d,1000000,sizeof(d));
        memset(dp,1000000,sizeof(dp));
        memset(dpp,0,sizeof(dpp));
        memset(v,0,sizeof(v));
        long long x,y,z;
        for(long long i=0;i<n;i++) cin>>s[i];//房间价值
        for(long long i=1;i<=m;i++)//邻接矩阵记录时间~权值
        {
            cin>>x>>y>>z;
            tag[x][y]=z;
            tag[y][x]=z;
        }

        //for(long long i=1;i<=7;i++)for(long long j=1;j<=7;j++)cout<<tag[i][j]<<' ';cout<<endl;

        long long i=0,j=1;
        dp[0]=0;
        d[0]=0;
        p[0]=a;
        v[0]=s[a];
        dq[0][0]=a;
        dpp[b]=s[b];
        int zz,l;
        while(i<j)//队列模拟
        {
            for(int k=0;k<=501;k++) dq[j][k]=0;
            long long w=p[i];
            if(p[i]==b||d[i]>dp[p[i]])
            {
                i=(i+1)%mod;
                continue;
            }
            for(long long k=0;k<=n;k++)
            {
                zz=0;
                if(tag[w][k])
                {
                    if(d[i]+tag[w][k]<=dp[k])
                    {
                        for(l=0;dq[i][l]!=0;l++)
                        {
                            dq[j][l]=dq[i][l];
                            if(k==dq[i][l])
                            {
                                //cout<<"z"<<endl;
                                zz=1;break;
                            }
                        }
                        if(zz) continue;
                        if(d[i]+tag[w][k]<dp[k]) dpp[k]=0;
                        dq[j][l]=k;
                        dp[k]=d[i]+tag[w][k];
                        d[j]=d[i]+tag[w][k];
                        p[j]=k;
                        v[j]=v[i]+s[k];
                       /* if(k==b)
                        {
                            long long sum=0;
                            for(l=0;dq[j][l]!=0;l++)
                            {
                                sum+=s[dq[j][l]];
                                cout<<dq[j][l]<<"    "<<sum<<' '<<s[dq[j][l]]<<' '<<dp[dq[j][l]]<<endl;
                            }
                            cout<<dpp[k]<<' '<<v[j]<<' '<<b<<' '<<i<<' '<<j<<endl;
                        }*/
                        dpp[k]=max(dpp[k],v[j]);
                        j=(j+1)%mod;
                    }
                }
            }
            //for(long long k=0;k<j;k++) cout<<setw(2)<<p[k]<<' ';cout<<endl;
            //for(long long k=0;k<j;k++) cout<<setw(2)<<d[k]<<' ';cout<<endl;
            //for(int k=0;k<j;k++) cout<<setw(2)<<v[k]<<' ';cout<<endl;
           // cout<<i<<' '<<j<<endl<<endl;
            //for(long long k=1;k<=7;k++){for(long long w=1;w<=7;w++)cout<<tag[k][w]<<' ';cout<<endl;}

            i=(i+1)%mod;
        }
        cout<<dp[b]<<' '<<dpp[b]<<endl;
    }
}

因为51nod 的这个题的数据的问题吧

因为 走回路的价值一定大于原本不走回路的价值 所以呢   

不标记路径更新最大值也是可以过的


#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <queue>
#include <map>
#include <cstring>
#include <iomanip>
using namespace std;
const long long mod=1500000;
long long tag[505][505];
long long dp[1500005];
long long dpp[1500005];
long long d[1500005];
long long p[1500005];
long long v[1500005];
long long s[1500005];
int main()
{
    long long n,m;
    while(cin>>n>>m)
    {
        long long a,b;
        cin>>a>>b;
        memset(tag,0,sizeof(tag));
        memset(d,1000000,sizeof(d));
        memset(dp,1000000,sizeof(dp));
        memset(dpp,0,sizeof(dpp));
        memset(v,0,sizeof(v));
        long long x,y,z;
        for(long long i=0;i<n;i++) cin>>s[i];
        for(long long i=1;i<=m;i++)
        {
            cin>>x>>y>>z;
            tag[x][y]=z;
            tag[y][x]=z;
        }
        
        //for(long long i=1;i<=7;i++)for(long long j=1;j<=7;j++)cout<<tag[i][j]<<' ';cout<<endl;
        
        long long i=0,j=1;
        dp[0]=0;
        d[0]=0;
        p[0]=a;
        v[0]=s[a];
        dpp[b]=s[b];
        while(i<j)
        {
            long long w=p[i];
            if(p[i]==b)
            {
                i++;
                continue;
            }
            for(long long k=0;k<=n;k++)
            {

                if(tag[w][k])
                {
                    if(d[i]+tag[w][k]<=dp[k])
                    {
                        if(d[i]+tag[w][k]<dp[k]) dpp[k]=0;
                        dp[k]=d[i]+tag[w][k];
                        d[j]=d[i]+tag[w][k];
                        p[j]=k;
                        v[j]=v[i]+s[k];
                        dpp[k]=max(dpp[k],v[j]);
                        j=(j+1)%mod;
                    }
                }
            }
            //for(long long k=0;k<j;k++) cout<<setw(2)<<p[k]<<' ';cout<<endl;
            //for(long long k=0;k<j;k++) cout<<setw(2)<<d[k]<<' ';cout<<endl;
            //for(int k=0;k<j;k++) cout<<setw(2)<<v[k]<<' ';cout<<endl;
           // cout<<i<<' '<<j<<endl<<endl;
            //for(long long k=1;k<=7;k++){for(long long w=1;w<=7;w++)cout<<tag[k][w]<<' ';cout<<endl;}

            i=(i+1)%mod;
        }
        cout<<dp[b]<<' '<<dpp[b]<<endl;
    }
}

刚刚秒懂 迪杰斯特拉算法

其实就是个贪心  每次选择最短的往下延伸 之后 每走完个点的出度  就标记已走过  ,之后选择剩下最短的延伸,更新每次的变的更小的,可以连接到点的值


#include<bits/stdc++.h>
#include <cstring>
using namespace std;
const int maxs=100000000;
int tag[505][505];//邻接矩阵
int dj[505];//标记时间最短
int vj[505];//标记是否走过
int sj[505];//标记每个房间的得分
int mj[505];//标记最大价值
int main()
{
    int n,m,a,b;
    while(cin>>n>>m>>a>>b)
    {
        memset(tag,1000000,sizeof(tag));
        //cout<<tag[0][0]<<endl;
        memset(vj,1,sizeof(vj));
        for(int i=0;i<n;i++) cin>>sj[i];
        int x,y,z;
        for(int i=0;i<m;i++)
        {
            cin>>x>>y>>z;
            tag[x][y]=z;
            tag[y][x]=z;
        }
        for(int i=0;i<n;i++)
        {
            dj[i]=tag[a][i];
        }
        dj[a]=0;
        mj[a]=sj[a];
        int mas,dv=a;
        for(int i=0;i<n;i++)
        {
            mas=maxs;
            for(int j=0;j<n;j++)
            {
                if(vj[j]>0&&dj[j]<mas)//寻找最小的值
                {
                    mas=dj[j];
                    dv=j;//记录最小的值是谁
                }
            }
            //cout<<dv<<endl;
            vj[dv]=0;
            for(int j=0;j<n;j++)//最小值可以延伸到哪个点
            {
                int sum=dj[dv]+tag[dv][j];
                //cout<<sum<<endl;
                if(dj[j]>sum)//更新可以变小的最小值
                {
                    dj[j]=sum;
                    mj[j]=mj[dv]+sj[j];
                }
                else if(dj[j]==sum)
                {
                    mj[j]=max(mj[j],mj[dv]+sj[j]);
                }
            }
            //for(int j=0;j<n;j++)cout<<dj[j]<<' ';cout<<"    "<<dv<<endl;
        }
        cout<<dj[b]<<' '<<mj[b]<<endl;
    }
}





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值