【最小环】心灵的抚慰 heart.pas/c/cpp

心灵的抚慰(heart.pas/c/cpp)

Problem:      heart.pas/c/cpp
Input:      heart.in
Output:      heart.out
Memory Limit:  256 MB
Time Limit:     1 sec

背景 Background

病毒问题解决后,神牛们的心灵久久不能平静。有个神牛因此已经“乱了”。他脑子中满是程序(否则怎么会成为神牛呢),而且他可以从一个程序联想到一些相似的程序。比如从程序1联想到2,从2联想到4,从4联想到6,从6联想到9……躺就像搜索一样一步一步越陷越深。不过同一种联想他只会联想一次。比如1、2之间他进行了一次联想,那么他不会再重新联想1到2,或2到1。眼看他又要乱了,有人突然想到,如果他刚开始时想到的程序能够经过联想若干次后联想回到原程序,那不就乱回来了吗?由于神牛马上就要开乱,请在1秒内告诉他,他需要想哪个程序,以便乱回来。

 

题目描述 Description

给出一些程序和他们互相联想的关系(如果两个程序A、B有联系,神牛可以从A联想到B,也可以从B联想到A,但A、B之间神牛最多联想一次),请告诉神牛他需要想哪个程序,以便在最短的时间内乱回来,并输出这个最短时间。

 

输入格式 Input Format (heart.in)

第一行有两个正整数N,M,分别表示程序个数和有多少对程序可以被神牛直接互相联想。

以下M行,每行三个正整数,分别表示一种联想的两端的程序的编号(从1开始),以及进行这种联想所需要的最短时间。

 

输出格式 Output Format (heart.out)

如果神牛无论如何都再也乱不回来了,输出“He will never come back.”。

如果神牛能够乱回来,请输出神牛会乱多长时间。

 

样例输入 Input Example

4 3

1 2 10

1 3 20

1 4 30

 

样例输出 Output Example

He will never come back.

 

数据范围

对于100% 的数据,n≤250。

 

 

 

题目意思很明了,是要我们求出最小环,当然就不能重复了

这里介绍两种方法

方法一:搜索——万能、高效的方法

在想不出怎么做的时候,搜索多少都是可以拿一点分的,毕竟(欧教说的)啥子算法都是枚举!

在深搜的时候我们需要记录如下状态dfs(x,sum),x表示当前正在哪一点,而sum表示当前已经用的最少时间,那怎么判断构成环了呢?我们可以定义一个全局变量,也可以加一个参数tar表示需要达到的目标位置,那么就只需要判断x=tar是就表示构成环了。
那在刚开始搜的时候不就是x=tar吗?所以我们还需要一个标记,true为当前不是第一步(就表示可以进行判断),而false就表示当前是刚开始搜,不能判断环

所以,最终我们就把状态设计成了四维的  dfs(x,flag,sum,tar)

至于怎么判断路是否走过了,可以开一个二维hash,h[i][j]表示i->j已经走过,当然标记的时候要双向标记,既要标记f[i][j],也要标记f[j][i]

都知道深搜效率是很低的,所以必须剪枝!判断是否可走我们已经进行了可行性剪枝,接下来我们只需要在dfs开头加一句最优化剪枝即可

加上最优化剪枝的程序可是比方法二的动规还快一点哦~(不过也不是所有)

C++ Code

/*
C++ Code
http://oijzh.cnblogs.com
By jiangzh
*/
#include<cstdio>
#include<cstring>
#define MAXN 260
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))

int n,m,dis[MAXN][MAXN];
bool map[MAXN][MAXN];
bool h[MAXN][MAXN];
int ans=0x3f3f3f3f;

void dfs(int x,bool flag,int sum,int tar)//x 当前点   flag 是否为第一个点   sum 目前总和   tar 目标点
{
    if(sum>ans) return;
    if(flag && x==tar) {ans=min(ans,sum);return;}
    
    for(int i=1;i<=n;i++)
        if(map[x][i] && !h[x][i])
        {
            h[x][i]=h[i][x]=true;
            dfs(i,true,sum+dis[x][i],tar);
            h[x][i]=h[i][x]=false;
        }
    
}

int main()
{
    freopen("heart.in","r",stdin);
    freopen("heart.out","w",stdout);
    scanf("%d%d",&n,&m);
    memset(dis,0x3f,sizeof(dis));
    int x,y,z;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        map[x][y]=map[y][x]=true;
        dis[x][y]=dis[y][x]=z;
    }
    
    for(int i=1;i<=n;i++)
        dfs(i,false,0,i);
    
    if(ans==0x3f3f3f3f) printf("He will never come back.");
    else printf("%d",ans);
    return 0;
}

  

 

 

 

方法二:floyd+动规求最小环——简单高效

都知道floyd可以求出任意点到任意点的最短距离,那么这一题求最小环当然也可以用floyd

不过从题目中可知,走过的路是不能再走的,所以我们要保证不重复

先说说floyd的原理,其状态其实是三维的f[i][j][k](只是把k就地滚动了),表示 i-->j 这条路用 1..k 这些点做中转所能取得的最短路,那么根据动规的思想,我们把它分成两类  i-->j用1..k-1做中转   和   i-->j用k做中转   ,用下面这一张图具体解释

dis[][]表示用floyd更新的最短路,而map[][]表示原来的长度
如果我们加上 k 这一状态,那么途中绿色部分就是 i-->j经过1..k-1作中转的最短路,那么现在我们用上 k 这个点我们只需要连上  i-k 和 k-j 就能构成一个环,由于dis[i][j]只用了1..k-1来做中转,而map[i][k]和map[k][j]用了k,所以路径是肯定不会重复的

用这个方法要特别注意,我赋初值习惯0x3f(pascal好像是$3f),结果后面加爆了,所以最多只能0x07(pascal是$07)!!!

C++ Code

/*
C++ Code
http://oijzh.cnblogs.com
By jiangzh
*/
#include<cstdio>
#include<cstring>
#define MAXN 260
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))

int n,m,dis[MAXN][MAXN];
int map[MAXN][MAXN];
int ans=0x07070707;

int main()
{
    freopen("heart.in","r",stdin);
    freopen("heart.out","w",stdout);
    scanf("%d%d",&n,&m);
    memset(dis,0x07,sizeof(dis));
    memset(map,0x07,sizeof(map));
    int x,y,z;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        map[x][y]=map[y][x]=z;
        dis[x][y]=dis[y][x]=z;
    }
    
    for(int k=1;k<=n;k++)
    {
        for(int i=1;i<k;i++)
            for(int j=i+1;j<k;j++)
                ans=min(ans,dis[i][j]+map[i][k]+map[k][j]);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
    }

    if(ans==0x07070707) printf("He will never come back.");
    else printf("%d",ans);
    return 0;
}

  

 

posted @ 2012-11-02 13:24  jiangzh  阅读(345)  评论(0编辑  收藏  举报