【普及模拟】城市连接
题目描述
天网恢恢,疏而不漏,经过上一次的抓捕,OI总部终于获取了怪盗的特征!现在,我们需要在基德再次来之前就把他的特征送到超级大牛的手上,可惜超级大牛不在总部,所以飞过海必须尽快把资料送到大牛家里。已知OI总部到大牛家中间有n-2个城城市,为了尽快达到目的地,飞过海通过水晶球了解到OI总部到大牛家的路线图,图上显示了n个城之间的连接距离。
可是飞过海很忙,需要请你来帮忙编写一个程序。
输入
输入文件中的第一行为一个整数n(n<=1000)。
第二行至第n+1行,每行有n个数。其中:第i+1行中表示第i个城市与其他城市之间的连接关系,0表示不连接,其它数字表示连接的距离。
输出
输出文件中的第一行为n个整数,表示所选的线路。
第二行中为一个数,表示最短距离。
样例输入
7
0 3 5 0 0 0 0
0 0 0 7 8 6 0
0 0 0 0 4 5 0
0 0 0 0 0 0 4
0 0 0 0 0 0 7
0 0 0 0 0 0 6
0 0 0 0 0 0 0
样例输出
1 2 4 7
14
一看到这道题,便想起了动态规划
的经典例题中的城市交通网,我本想套进去的,可是事实
证明不行。
因为它的动态转方程是:f[i]=min(f[k]+a[i][k],f[i]);
所以,假设i=5,k=2,并且 f[k]+a[i][k]<f[i];
这样表面看起来好像是对了,但是如果我们,f[i]表示第i个城市到第n个城市距离。
那么就错了。f[2]假设到n的路径是2->3->7,而f[5]假设是5->6->7!
想必大家已经明白了吧!
于是我们便可以用最短路,又因为是求单源路径,
我们就可以没必要用SPFA!dijk即可
code:
#include <stdio.h>
#include <string.h>
const int inf = 99999999;
struct edge {
int u, v, w;
}e[1000010];
int vis[1010], dis[1010], f[1010], p[1010], q[1010], cnt, n;
void Add(int u, int v, int w)
{
e[++cnt] = (edge){f[u], v, w};
f[u] = cnt;
}
void Dijkstra(int s)
{
int k;
for (int i = 0; i < n; i++)
{
dis[i] = inf;
vis[i] = 0;
}
dis[s] = 0;
vis[s] = 1;
for (int i = 0; i < n; i++)
{
int min = inf;
for (int j = 0; j < n; j++)
if (!vis[j] && min > dis[j])
min = dis[k = j];
vis[k] = 1;
for (int j = f[k]; j; j = e[j].u)
{
int v = e[j].v;
if (e[j].w < inf && !vis[v] && dis[v] > dis[k] + e[j].w)
{
p[v] = k;
dis[v] = dis[k] + e[j].w;
}
}
}
}
int main()
{
freopen("city.in","r",stdin);
freopen("city.out","w",stdout);
int m, w;
while (~scanf("%d", &n))
{
cnt = 0;
memset(f, 0, sizeof(f));
memset(p, -1, sizeof(p));
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
{
scanf("%d", &w);
if (!w)
Add(i, j, inf);
else Add(i, j, w);
}
Dijkstra(0);
int k = 0, a = n - 1;
q[k++] = a + 1;
while (p[a] != -1)
{
a = p[a];
q[k++] = a + 1;
}
for (int i = k - 1; i > 0; i--)
printf("%d ", q[i]);
printf("%d\n%d\n", q[0], dis[n - 1]);
}
return 0;
}