你来到一个迷宫前。该迷宫由若干个房间组成,每个房间都有一个得分,第一次进入这个房间,你就可以得到这个分数。还有若干双向道路连结这些房间,你沿着这些道路从一个房间走到另外一个房间需要一些时间。游戏规定了你的起点和终点房间,你首要目标是从起点尽快到达终点,在满足首要目标的前提下,使得你的得分总和尽可能大。现在问题来了,给定房间、道路、分数、起点和终点等全部信息,你能计算在尽快离开迷宫的前提下,你的最大得分是多少么?
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;
}
}