Ural 1004 ,很简单的题,但是测试要求很BT我觉得
Translate:URAL/1004
Sightseeing trip 观光旅游Time Limit: 2 secondMemory Limit: 16M
目录[隐藏] |
[编辑] Background
在桑给巴尔岛的Adelton城镇上有一个旅游机构。城镇里有许多景点,于是它们决定为其客户提供游览这些景点的服务。为了从这些景点中尽可能获利,这个旅游机构通过了一个精明决定:必须找一条起点与终点相同的最短路线。
[编辑] Problem
你的任务是编写一条程序来找类似的的一条路线。在这个镇上,有N个十字路口(编号1至N),两个十字路口之间可以有多条道路连接,有M条双向行驶的道路(编号为1至M)。但没有一条道路从一个十字路口出发又回到同一个路口。每一条观光路线都是由一 些路组成的,这些道路序号是:y_1, ..., y_k,且k>2。第y_i(1<=i<=k-1)号路是连接第x_i号十字路口和第x_{i+1}号十字路口的;其中第y_k号路是连接第x_k号十字路口和第x_1号十字路口。而且所有的这些x_1,...,x_k分别代表不同路口的序号。在 某一条观光路线上所有道路的长度的和就是这条观光路线的总长度。换言之L(y_1)+L(y_2)+...+L(y_k) 的和 L(y_i)就是第y_i 号观光路线的长度。你的程序必须找出类似的一条路线:长度必须最小,或者说明在这个城镇上不存在这条观光路线。
[编辑] Input
含几组测试数据。每一组数据的第一行包含两个正整数:十字路口的个数N(N<=100),另一个是道路的 数目M(M<10000)。接下来的每一行描述一条路:每一行有三个正整数:这条路连接的两个路口的编号,以及这条路的长度(小于500的正整数)。最后以`-1`结束。
[编辑] Output
每一行输出都是一个答案。如果这条观光路线是不存在的话就显示“No solution.”(PS:有句点);或者输出这条最短路线的经过所有十字 路口的序号,每一个序号之间用一个空格符隔开,这样更能说明这条路线是如何得出来的。也就是用从x_1到x_k描述一条观光路线。假如满足最短长度的观光路线不止一条,输出其中的任一条即可。
[编辑] Sample Input
5 7 1 4 1 1 3 300 3 1 10 1 2 16 2 3 100 2 5 15 5 3 20 4 3 1 2 10 1 3 20 1 4 30 -1
[编辑] Sample Output
1 3 5 2 No solution.
就是一个Floyd求最小环。基本代码不用讲,求最小环的原理很简单,可以参见Wikipedia的证明。
记录方案有很多方法,Wzz跟我讲过迭代加深的方法,但是没有听懂。。
我的方法是最容易理解的,但是有一个地方很容易打错,应该是很多人都遭过的,上网看题解的时候,很多人都提到过这个地方。可是我还是错了,调了一天才发现是这里有问题
一定要注意,虽然最小环和最短路是双进程DP,但是这两个是紧密相关的,不能独立对待。因此可以考虑这样一种情况:
(虚线表示路,实线和虚线加起来表示环)
当某一时刻找到了A+b这一个最小环,此时我们g数组中记录下了甲乙之间最短路的中转点。
后来,我们找到了另一条甲乙的最短路,假设此路经过点丙,因此此路可以更新最短路,但是不一定能更新最小环,因此g数组变了,但是最小环不能更新。
我们输出结果的时候,是根据g来输出的,但是g被更改了。因此必须在每次求得最小环的时候记录下当前的g!!!
输出的时候,用一个递归,模拟二分过程,每次找[l,m]和[m+1,r]这两个区间
接下来讲讲很坑爹的地方:
1、如果有哪一个变量不初始化,基本上就WA第一组了。
2、如果有哪一个数组不初始化,基本上就Crash第一组了。
3、如果行末多了空格,就不清楚能得几分了。
#include <cstdio>
#define inf (0x7f7f7f7f)
long f[110][110];
long g2[110][110];
long path[110][110];
long f2[110][110];
long bm[110][110];
long print[110];
long cnt = 0;
long n;
long m;
long ans = 0x7f7f7f7f;
long sta;
long endd;
long midd;
void make_path()
{
for (long i=1;i<n+1;i++)
{
for (long j=1;j<n+1;j++)
{
path[i][j] = g2[i][j];
}
}
}
void dp()
{
for (long k=1; k<n+1; k++)
{
for (long i=1; i<k; i++)
{
if (i == k) continue;
for (long j=i+1; j<k; j++)
{
if (j==k || j==i) continue;
if (f2[j][i]<inf&&bm[i][k]<inf&&bm[k][j]<inf)
if (ans > f2[j][i]+bm[i][k]+bm[k][j])
{
ans = f2[j][i]+bm[i][k]+bm[k][j];
make_path();
sta = i;
endd = j;
midd = k;
}
}
}
for (long i=1; i<n+1; i++)
{
if (i==k) continue;
for (long j=1; j<n+1; j++)
{
if (j==i || j==k) continue;
{
if (f2[i][k]<inf&&f2[k][j]<inf)
{
if (f2[i][j] > f2[i][k]+f2[k][j])
{
f2[i][j] = f2[i][k]+f2[k][j];
g2[i][j] = k;
}
}
}
}
}
}
}
void output(long i,long j)
{
if (path[i][j] == 0) return;
output(i,path[i][j]);
print[++cnt] = path[i][j];
output(path[i][j],j);
}
int main()
{
freopen("trip.in","r",stdin);
freopen("trip.out","w",stdout);
scanf("%ld",&n);
while (n!=-1)
{
scanf("%ld",&m);
//
//Initialization
/
cnt = sta = endd = midd = 0;
ans = 0x7f7f7f7f;
for (long i=1; i<n+1; i++)
{
print[i] = 0;
for (long j=1; j<n+1; j++)
{
g2[i][j] = 0;
path[i][j] = 0;
bm[i][j] = f[i][j] = f2[i][j] = inf;
}
}
///
for (long i=1; i<m+1; i++)
{
long x;long y;long l;
scanf("%ld%ld%ld",&x,&y,&l);
if (f2[x][y] > l) f2[x][y]=bm[x][y]=l;
if (f2[y][x] > l) f2[y][x]=bm[y][x]=l;
}
dp();
if (ans < inf)
{
print[++cnt] = sta;
output(sta,endd);
print[++cnt] = endd;
if (midd!=path[sta][endd])
print[++cnt] = midd;
for (long i=1;i<cnt;i++)
{
printf ("%ld ",print[i]);
}
printf("%ld\n",print[cnt]);
}
else
printf("No solution.\n");
scanf("%ld",&n);
}
return 0;
}