您的位置:首页 > 其它

HDU1385 【输出字典序最小的最短路】

2013-09-04 21:24 169 查看
这题经过的结点比较好处理。

主要是字典序的处理。

先是floyd做法,采用记录后驱的方法。  path[i][j]=j【初始化。。。】

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstring>
using namespace std;

const int maxn=5000;
const int INF=100000000;

int n;
int node[maxn];
int dist[maxn][maxn];
int path[maxn][maxn];

void floyd()
{
for(int i=1;i<=n;i++)//初始化 有一种后驱的感觉
for(int j=1;j<=n;j++)
path[i][j]=j;

for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
int temp=dist[i][k]+dist[k][j]+node[k];
if(dist[i][j]>temp)
{
dist[i][j]=temp;
path[i][j]=path[i][k];
}
if(dist[i][j]==temp)
{
if(path[i][j]>path[i][k])
path[i][j]=path[i][k];
}
}
}

int main()
{
int a,be,en;
while(scanf("%d",&n)&&n)
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
scanf("%d",&a);
if(a!=-1) dist[i][j]=a;
else dist[i][j]=INF;
}
for(int i=1;i<=n;i++) scanf("%d",&node[i]);

floyd();

int kcase=0;
while(1)
{
if(kcase!=0) printf("\n");
kcase++;
scanf("%d%d",&be,&en);
if(be==-1&&en==-1) break;
printf("From %d to %d :\n",be,en);
printf("Path: ");
printf("%d",be);

int temp=be;
while(temp!=en)
{
printf("-->%d",path[temp][en]);
temp=path[temp][en];
}
printf("\n");

printf("Total cost : %d\n",dist[be][en]);

}
}
return 0;
}


接下来是spfa的做法。















































又提交了20+WA

本来就是想练一下输出前驱,结果。。。 某个地方竟然犯了一个我没想到的错。

首先是比较前面结点字典序时,应该从头开始。然后就是这个我会记一辈子的错了。。

邻接表做法

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;

const int maxn=10005,INF=10000000;

queue<int> q;
bool inq[maxn*2];
int first[maxn*2];
int next[maxn*2];
int p[maxn];
int u[maxn*2],v[maxn*2],w[maxn*2],d[maxn*2];
int str1[maxn],str2[maxn];
int n,m;
int map[maxn][maxn];
int node[maxn];
int dis[maxn];

void spfa(int be)
{
while(!q.empty()) q.pop();
for(int i=0;i<n;i++)
d[i]=(i==be?0:INF);
memset(inq,0,sizeof(inq));
memset(p,0,sizeof(p));
q.push(be);
while(!q.empty())
{
int x=q.front();q.pop();
inq[x]=false;
for(int e=first[x];e!=-1;e=next[e])
{
if(d[v[e]]>d[x]+w[e])
{
d[v[e]]=d[x]+w[e];
p[v[e]]=x;
if(!inq[v[e]])
{
inq[v[e]]=true;
q.push(v[e]);
}
}
else if(d[v[e]]==d[x]+w[e])//这一块遍历前趋没问题
{
int l1=0,l2=0;

int temp=v[e];
while(temp!=be)
{
str1[l1++]=temp;
temp=p[temp];
}

temp=x;
while(temp!=be)
{
str2[l2++]=temp;
temp=p[temp];
}

for(int i=l1-1,j=l2-1;i>=0&&j>=0;i--,j--)
{
if(str1[i]>str2[j])
{
p[v[e]]=x;
break;
}
else if(str1[i]<str2[j]) break;
}
if(!inq[v[e]])
{
inq[v[e]]=true;
q.push(v[e]);
}
}

}
}
}

int main()
{
int a,b;
while(scanf("%d",&n)!=EOF)
{
if(!n) break;
memset(first,-1,sizeof(first));
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
scanf("%d",&map[i][j]);
}
for(int i=0;i<n;i++) scanf("%d",&node[i]);
int cnt=0;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
if(map[i][j]==-1||i==j) continue;
else
{
next[cnt]=first[i];
first[i]=cnt;
}
w[cnt]=map[i][j]+node[j];
u[cnt]=i;
v[cnt]=j;
cnt++;
}

while(scanf("%d%d",&a,&b)){
if(a==-1 && b==-1)break;
if(a==b){
printf("From %d to %d :\nPath: %d\nTotal cost : 0\n\n",a,b,a);
continue;
}
a--;b--;
spfa(a);
int l=0;int x=b;
while(p[x]!=a){
dis[l++]=p[x];
x=p[x];
}
printf("From %d to %d :\nPath: %d-->",a+1,b+1,a+1);
for(int i=l-1;i>=0;i--){
printf("%d-->",dis[i]+1);
}
printf("%d\nTotal cost : %d\n\n",b+1,d-node[b]);
}
}
return 0;
}

[b]哈哈,想了终于明白这个地方 temp=v[e]了。


比如1 2 4 还有一个是1 2 3 4 显然第二种比第一种字典序更靠前。

但自己不是temp=v[e]的话就少了这种情况。

如果是1 2 3 4和1 2 4则可以成功。

自己可以生成一个案例。

终于明白,呵~~~~~~~~~~~~

错这么多次也是值得的,至少自己验证了模板和自己某些方面的不严谨性。

 

4

-1 1 -1 -1

1 -1 2 3

-1 2 -1 1

-1 3 1 -1

0 0 0 0

1 4

From 1 to 4 :

Path: 1-->2-->4

Total cost : 4


这个样例是错的。   神一般的解放呀


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: