【最短路】民大风景(prim判环)

来源:互联网 发布:网络交友新时空课文 编辑:程序博客网 时间:2024/04/29 18:03

民大风景

时间限制(普通/Java) : 1000 MS/ 3000 MS          运行内存限制 : 65536 KByte
总提交 : 76            测试通过 : 17 

描述

民大新校区中有n个景点可去,比如小镇,南大门,映月潭,梦云湖等等。YKY近来闲的无事,便想游历一下校园。景点之间都有一条最短的直通的路,然而YKY只会去走其中一些,因为“妹子多”,YKY说“妹子之所在,便是我的去处”。由于太过DS,YKY懒得走太多路,又不愿去重复的地方,他只想绕尽量小的圈回到原地。比如他从v1点出发,最后由v1,v2,...vk,v1回到v1(k>=3)。现在YKY需要你帮他找一条这样的路线,并且路程最短。

输入

多组测试数据
第一行是2个整数N和M(N <= 100, M <= 10000),代表景点的个数和道路的条数。
接下来的M行里,每行包括3个整数a,b,c.代表a和b之间有一条通路,并且有c米长(0<c <= 100)

输出

对于每个测试实例,如果能找到这样一条路线的话,输出路程的最小值。如果找不到的话,输出"It's impossible.".

样例输入

3 3
1 2 1
2 3 1
1 3 1
3 3
1 2 1
1 2 3
2 3 1

样例输出

3
It's impossible.


这题的题意就是判断一个树中的最短环。开始没做出来是没有理解prim算法

prim算法就是三个for循环:

for(k=1;k<=n;k++)

for(i=1;i<=n;i++)

for(j=1;j<=i;j++)

第一个K表示i点到j点经过小于等于k点的点的最短路径,这样一步步循环到k=n时即为i到j点经过N个点的最短路径。

我以前只是硬记住了算法程序,没有弄清楚本质,这题做时就不知道该怎么办。

起初想的是求出dis[I][I]就行了,但可能出现回环的可能,即1—》2然后2—》1。也想到判断dis[i][k]!=dis[k][i],但显然是错的,碰巧一样了怎么办。于是思路陷入了死路。后来看了别人代码,发现是求出dis[i][j]后一个个寻找中间点K,如果K!=i&&k!=j,那么就不会出现回环了。值得注意的是求出小于等于K的dis[i][j]后不能继续判断经过小于K的点的最短环,因为dis[i][j]中可能已经经过了K点,所以要判断经过K+1的点的最短环。

也就是说:

求dis[i][j]经过K点的最短环,那么这时的dis[i][j]必须是中间点小于K的最短路径。所以可以在一个循环里面把求最短路和最短环写在一起。

AC代码如下:

#include<stdio.h>
#include<iostream>
using namespace std;
const int Max=110;
int Map[Max][Max],dis[Max][Max],ans,n;
int minn(int x,int y)
{
    return x>y?y:x;
}
void Floyd()
{
    int i,j,k;
    for(i=1;i<=n;i++)
        for(j=i+1;j<=n;j++)
            if(i!=1&&j!=1)
            ans=minn(ans,dis[i][j]+Map[i][1]+Map[j][1]);
    for(k=1;k<=n;k++)
    {
        for(i=1;i<=n;i++)
        {
            for(j=1;j<i;j++)
           {
            if(dis[i][j]>dis[i][k]+dis[k][j])
            dis[i][j]=dis[j][i]=dis[i][k]+dis[k][j];
           // cout<<dis[j][i]<<" ";
            if(i!=k+1&&j!=k+1&&k+1<=n)
            ans=minn(ans,dis[i][j]+Map[i][k+1]+Map[j][k+1]);
          //  cout<<ans<<endl;
           }
      //  cout<<endl;
        }

    }
}
int main()
{
    int m,i,j,a,b,c;
    while(~scanf("%d%d",&n,&m))
    {
        for(i=1;i<=n;i++)
            for(j=1;j<=n;j++)
            {
                if(i==j)
                {
                    Map[i][j]=dis[i][j]=0;
                    continue;
                }
                Map[i][j]=1000000;
                dis[i][j]=1000000;
            }
        while(m--)
        {
            scanf("%d%d%d",&a,&b,&c);
            if(c<Map[a][b])
            {
                Map[a][b]=Map[b][a]=c;
                dis[a][b]=dis[b][a]=c;
            }
        }
        if(n<=2)
        {
            printf("It's impossible.\n");
            continue;
        }
        ans=1000000;
        Floyd();
        if(ans>=1000000)
            printf("It's impossible.\n");
        else
            printf("%d\n",ans);
    }
    return 0;
}

0 0
原创粉丝点击