route.in
输出文件:
route.out
简单对比
【问题描述】
X城有一个含有N个节点的通信网络,在通信中,我们往往关心信息从一个节点I传输到节点J的最短路径。遗憾的是,由于种种原因,线路中总有一些节点会出故障,因此在传输中要避开故障节点。
任务一:在己知故障节点的情况下,求避开这些故障节点,从节点I到节点J的最短路径S0。
任务二:在不考虑故障节点的情况下,求从节点I到节点J的最短路径S1、第二最短路径S2。
【输入文件】
第1行: N I J (节点个数 起始节点 目标节点)
第2—N+1行: Sk1 Sk2…SkN (节点K到节点J的距离为SkJ K=1,2,……,N)
最后一行: P T1 T2……Tp (故障节点的个数及编号)
【输出文件】
S0 S1 S2 (S1<=S2 从节点I到节点J至少有两条不同路径)
【输入输出样例】
route.in
5 1 5
0 10 5 0 0
10 0 0 6 20
5 0 0 30 35
0 6 30 0 6
0 20 35 6 0
1 2
route.out
40 22 30
【约束条件】
(1)N<=50 N个节点的编号为1,2,…,N
(2)Skj为整数,Skj<=100,(K,J=1,2…,N 若Skj=0表示节点K到节点J没线路)
(3)P<=5
此题是一个典型的最短路问题,s0,s1好求,基本的最短路,spfa和dijs均可顺利解决,s2解决次短路有不少方法,我是用a*解决,但此题要注意,不能有自反边,所以在a*的时候要注意不能反复走同一条边,具体解决参考代码。
#include
#include
#include
using namespace std;
#define Mem(arr,val) memset(arr,val,sizeof(arr));
const int maxn=55;
const int maxe=maxn*maxn;
struct Edge
{
int to,data,next;
};
struct Node
{
int now,g,f,fa;
Node(){};
Node(int x,int y,int z,int w){now=x;g=y,f=z;fa=w;}
bool operator < (const Node &a)const
{
if(f==a.f)return g>a.g;
return f>a.f;
}
};
Edge e[maxe],re[maxe];
int n,p,st,en,len,head[maxn],rehead[maxn],f[maxn];
int dis[maxn];
void Init();
void Insert(int,int,int);
void Spfa1(int);
void Spfa2(int);
int Astar(int,int);
int main()
{
freopen("route.in","r",stdin);
freopen("route.out","w",stdout);
Init();
Spfa2(st);
Spfa1(en);
//for(int i=1;i<=n;i++)printf("%d ",dis[i]);printf("\n");
printf("%d %d\n",dis[st],Astar(st,en));
return 0;
}
void Init()
{
Mem(head,-1);Mem(rehead,-1);
Mem(e,0);Mem(re,0);Mem(f,0);
scanf("%d%d%d",&n,&st,&en);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
int x;scanf("%d",&x);
if(x) Insert(i,j,x);//把临接矩阵转成邻接表存储
}
scanf("%d",&p);
for(int i=1;i<=p;i++)
{
int x;
scanf("%d",&x);f[x]=1;
}
}
void Insert(int x,int y,int z)
{
len++;
e[len].to=y;e[len].data=z;e[len].next=head[x];head[x]=len;
re[len].to=x;re[len].data=z;re[len].next=rehead[y];rehead[y]=len;//如果是有向边需存储你像边,此题不需要
}
void Spfa1(int st)//求无坏点的最短路
{
queue q;bool flag[maxn]={0};
Mem(dis,0x7f);
flag[st]=0;dis[st]=0;q.push(st);
while(!q.empty())
{
int k=q.front();q.pop();flag[k]=0;
for(int i=head[k];i!=-1;i=e[i].next)
{
int j=e[i].to;
if(dis[j]>dis[k]+e[i].data)
{
dis[j]=dis[k]+e[i].data;
if(!flag[j])
{
flag[j]=1;
q.push(j);
}
}
}
}
//for(int i=1;i<=n;i++)printf("%d ",dis[i]);
}
void Spfa2(int x)//求有坏点的最短路
{
bool flag[maxn]={0};
int dis[maxn];Mem(dis,0x7f);
queueq;flag[x]=1;dis[x]=0;q.push(x);
while(!q.empty())
{
int k=q.front();q.pop();flag[k]=0;
for(int i=head[k];i!=-1;i=e[i].next)
{
int j=e[i].to;//如果此点为坏点直接跳过
if(f[j])continue;
if(dis[j]>dis[k]+e[i].data)
{
dis[j]=dis[k]+e[i].data;
if(!flag[j])
{
q.push(j);flag[j]=1;
}
}
}
}
printf("%d ",dis[en]);
}
int Astar(int s,int t)
{
priority_queue q;
int fa[maxn];Mem(fa,-1);
int tot=0;q.push(Node(s,0,dis[s],fa[s]));//正常需要传递3个参数即可,但为了处理
//自返边传递了当前点的父节点。第一个参数是当前节点,第二个参数是当前点到源点的距离
// 第三个参数是当前节点到终点的最短距离,第四个参数是当前节点的父亲节点
while(!q.empty())
{
Node x=q.top();q.pop();
if(x.now==t)//如果当前节点是终点,说明找到了一条第tot+1短的边
{
tot++;
if(tot==2)return x.g;
}
for(int i=head[x.now];i!=-1;i=e[i].next)
{
if(x.fa==e[i].to)continue;//如果当前边指向了其父节点说明自反了,跳过
int now=e[i].to,g=x.g+e[i].data,f=now+g;
fa[now]=x.now;
q.push(Node(now,g,f,fa[now]));
}
}
return -1;
}