HDU1385 【输出字典序最小的最短路】
2013-09-04 21:24
169 查看
这题经过的结点比较好处理。
主要是字典序的处理。
先是floyd做法,采用记录后驱的方法。 path[i][j]=j【初始化。。。】
接下来是spfa的做法。
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
又提交了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
这个样例是错的。 神一般的解放呀
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
主要是字典序的处理。
先是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的做法。
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
又提交了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
这个样例是错的。 神一般的解放呀
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/wail.gif)
相关文章推荐
- HDU1385 【输出字典序最小的最短路】
- uva 10537 - The Toll! Revisited (逆向思维+最短路+输出字典序最小路径)
- UVA 10537 The Toll! Revisited(最短路变形+输出字典序最小路径)
- Minimum Transport Cost hdu 点权和边权的最短路+输出字典序最小的路径
- hdu1385 Minimum Transport Cost (floyd输出字典序最小的路径)
- 多种排列方式满足条件,输出按照名字排列字典序最小的一个
- poj 2337 欧拉回路按照最小字典序输出+注意为了按最小字典序怎么处理邻接表
- 二分图最大匹配 输出字典序最小的方案 poj 3715
- ZOJ - 1729(最小表示法。 <<然后输出字典序最小
- UVA 10537 The Toll! Revisited(dijkstra输出字典序最小的路径)
- hdoj 4857 逃生 【拓扑排序 输出字典序最小解】
- poj 1041(欧拉回路+输出字典序最小路径)
- hdu 1385 最短路+输出字典序--好题
- Ideal Path,uva1599/hdu 3760(最短路中字典序最小的路径)
- uva116(dp,多段图的最短路,求最小的字典序)
- ZOJ - 1729(最小表示法。 <<然后输出字典序最小
- POJ 1815 Friendship(最小割+字典序输出割点)
- HDU 1814 Peaceful Commission(2-sat 输出字典序最小解 )
- UVa 1599 (字典序最小的最短路) Ideal Path
- HDU - 1385 Minimum Transport Cost (最短路dijkstra+打印字典序最小路径)