【最小环】Sightseeing Trip

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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值