SSL-1763 观光旅游(求无向图的最小环问题)

49 篇文章 0 订阅

目录

题面

Description

  在桑给巴尔岛的Adelton城镇上有一个旅游机构。它们决定在提供许多的其它吸引之外,再向客人们提供旅游本镇的服务。 为了从提供的吸引服务中尽可能地获利,这个旅游机构接收了一个精明决定:在相同的起点与终点之间找出一最短路线。

Input

  你的任务是编写一条程序来找类似的的一条路线。在这个镇上,有N个十字路口(编号1至N),两个十字路口之间可以有多条道路连接,有M条道路(编号为1至M)。但没有一条道路从一个十字路口出发又回到同一个路口。每一条观光路线都是由一些路组成的,这些道路序号是:y1, …, yk,且k>2。第yi(1<=i<=k-1)号路是连接第xi号十字路口和第x[i+1]号十字路口的;其中第yk号路是连接第xk号十字路口和第x[k+1]号十字路口。而且所有的这些x1,…,xk分别代表不同路口的序号。在某一条观光路线上所有道路的长度的和就是这条观光路线的总长度。换言之L(y1)+L(y2)+…+L(yk)的和, L(yi)就是第yi号观光路线的长度。你的程序必须找出类似的一条路线:长度必须最小,或者说明在这个城镇上不存在这条观光路线。

Output

每组数据的第一行包含两个正整数:十字路口的个数N(N<=100),另一个是道路的 数目M(M<10000)。接下来的每一行描述一条路:每一行有三个正整数:这条路连接的两个路口的编号,以及这条路的长度(小于500的正整数)。

Sample Input

  每一行输出都是一个答案。如果这条观光路线是不存在的话就显示“No solution”;或者输出这条最短路线的长度。

Sample Output

只有一行,表示这个图的最短路。

样例1

5 7
1 4 1
1 3 300
3 1 10
1 2 16
2 3 100
2 5 15
5 3 20

样例2

4 3
1 2 10
1 3 20
1 4 30

样例1 输出

61

样例2 输出

No solution

思路

图的最小环问题,本人用了四种方法,但只有两种A了,另外两种还找不到错误,望各位大佬看看。。。

代码 of 30

#include<cstdio>//这是一种并查集的解法,可以过样例,拿30分,至今没找到其它错误,但仍然WA,这里就不详细解释了
#include<cstring>
#define r(i,a,b) for(int i=a;i<=b;i++)
#define t(a) (a<<3)+(a<<1)+c-48
using namespace std;
int f[101],l[10001],n,m,u[101],v[101];
int w,ans=2147483647,tot,now,to,time;
struct node
{
    int w,to,next;
}a[10001];
void add(int u,int v,int w)
{
    a[++tot].next=l[u];
    a[tot].to=v;
    a[tot].w=w;
    l[u]=tot;
}
int min(int x,int y){return x<y?x:y;}
int read()
{
    char c;int f=0;
    while((c=getchar())<48||c>57);f=t(f);
    while((c=getchar())>=48&&c<=57) f=t(f);
    return f;
}
int find(int x)
{
    return x==f[x]?x:f[x]=find(f[x]);
}
void dfs(int x,int dep)
{
    if(dep>now) return;
    if(x==to&&dep) {now=dep;return;}
    for(int j=l[x];j;j=a[j].next)
        if(dep<now&&!(x==to&&dep>0))
          {dfs(a[j].to,dep+a[j].w);time++;}
            else if(time>m) break;
}
int main()
{
    n=read();m=read();
    r(i,1,n) f[i]=i;
    r(i,1,m)
    {
        u[i]=read();v[i]=read();w=read();
        add(u[i],v[i],w);
    }
    r(i,1,m)
     {
        int x=find(u[i]),y=find(v[i]);
        if(x==y)
        {
            time=0;now=2147483647;to=v[i];
            dfs(v[i],0);
            ans=min(ans,now);
            continue;
        }
        f[y]=x;
      }
    if(ans!=2147483647)
    printf("%d",ans);else
    puts("No sulution");
}

代码 of 40

#include<cstdio>//这是一种SPFA的做法,跟第一题一样,拿不到全分,也没有找到错误,其实它的思路和dij是一样的,都是删边求最短路,再加距离,但只能过40分,这里也不详细解释
#include<queue>
#include<vector>
#define r(i,a,b) for(int i=a;i<=b;i++)
#define t(a) (a<<3)+(a<<1)+c-48 
#define INF 2147483648>>2
using namespace std;
int f[101],u[101],v[101],n,m,l[101][101],dis[101];
vector<int>a[101];
int w,ans=2147483647,tot,now,to;
int min(int x,int y){return x<y?x:y;}
int read()
{
    char c;int f=0;
    while((c=getchar())<48||c>57);f=t(f);
    while((c=getchar())>=48&&c<=57) f=t(f);
    return f;
}
int spfa(int x,int y)
{
        r(j,1,n) dis[j]=INF;
        dis[x]=0;
        queue<int>q;bool vis[101]={0};vis[x]=true;q.push(x);
        do
        {
            int u=q.front();q.pop();
            r(i,0,a[u].size()-1)
             {
                int v=a[u][i],w=l[u][v];
                if(dis[u]+w<dis[v])
                {
                    dis[v]=dis[u]+w;
                    if(!vis[v])
                     {
                        q.push(v);
                        vis[v]=true;
                     }
                }
             }
            vis[u]=false;
        }while(!q.empty());
        return dis[y];
}
int main()
{
    /*freopen("first.in","r",stdin);
    freopen("first.out","w",stdout);*/
    n=read();m=read();
    r(i,0,99) r(j,i+1,100) l[i][j]=l[j][i]=INF;
    r(i,1,m)
    {
        u[i]=read();v[i]=read();w=read();
        a[u[i]].push_back(v[i]);
        a[v[i]].push_back(u[i]);
        l[u[i]][v[i]]=l[v[i]][u[i]]=w;
    }
    r(i,1,m)
     {
        int t=l[u[i]][v[i]];
        l[u[i]][v[i]]=l[v[i]][u[i]]=INF;
        ans=min(ans,spfa(u[i],v[i])+t);
        l[u[i]][v[i]]=l[v[i]][u[i]]=t;
     }
    if(ans>=50000000)
    puts("No solution");else printf("%d",ans);
}

O(mn2) O ( m n 2 )

代码 of dijkstra

#include<cstdio>//这个效率要低于floyed,因为这张图比较密集,枚举边的时间更长了。
#define INF 2147483647>>2
#define N 101
#define r(i,a,b) for(int i=a;i<=b;i++)
#define t(a) (a<<3)+(a<<1)+c-48
using namespace std;
int dis[N],l[N][N],n,ans=INF,m,x[N*N],y[N*N],w[N*N];
int min(int x,int y){return x<y?x:y;}
int read()
{
    char c;int f=0;
    while((c=getchar())<48||c>57);f=t(f);
    while((c=getchar())>=48&&c<=57) f=t(f);
    return f;
}
int dijkstra(int u,int v)//dij不解释
{
    bool vis[N]={0};int minn=0,k=0;
    for(int i=1;i<=n;i++)
     dis[i]=l[u][i];
    vis[u]=true;dis[u]=0;
    r(i,1,n-1)
    {
        minn=INF;
        k=0;
        r(j,1,n)
         if(!vis[j]&&dis[j]<minn)
          {
            minn=dis[j];
            k=j;
          }
        if(!k) break;
        vis[k]=true;
        r(j,1,n)
         if(dis[k]+l[k][j]<dis[j])
          dis[j]=dis[k]+l[k][j];
    }
    return dis[v];
}
int main()
{
    n=read();m=read();
    r(i,0,N-1)
     r(j,0,N-1)
      l[i][j]=INF;
    r(i,1,m) 
     {
        x[i]=read();y[i]=read();w[i]=read();
        l[x[i]][y[i]]=l[y[i]][x[i]]=w[i];//初始化
     }
    r(i,1,m)
     {
        int t=l[x[i]][y[i]]=l[y[i]][x[i]];
        l[x[i]][y[i]]=l[y[i]][x[i]]=INF;//删边
        ans=min(ans,dijkstra(x[i],y[i])+t);//计算
        l[x[i]][y[i]]=l[y[i]][x[i]]=t;//复边
     }
    if(ans>=50000000) puts("No solution");else
    printf("%d",ans);//特判
}

O(n3) O ( n 3 )

代码 of floyed

#include<cstdio>//这个代码最短的反而AC了,十分神奇
#include<cstring>
#define INF 2147483647>>2
#define N 101
#define r(i,a,b) for(int i=a;i<=b;i++)
#define t(a) (a<<3)+(a<<1)+c-48
using namespace std;
int ans=INF,l[N][N],n,m,x,y,w,dis[N][N];
int min(int x,int y){return x<y?x:y;}
int read()
{
    char c;int f=0;
    while((c=getchar())<48||c>57);f=t(f);
    while((c=getchar())>=48&&c<=57) f=t(f);
    return f;
}
int main()
{
    n=read();m=read();
    memset(dis,127>>2,sizeof(dis));
    memset(l,127>>2,sizeof(l));
    r(i,1,m)
     {
        x=read();y=read();w=read();
        l[x][y]=l[y][x]=w;
        dis[x][y]=dis[y][x]=w;//初始化
     }
    r(k,1,n)
     {
        r(i,1,n)
         r(j,i+1,n)
          ans=min(ans,dis[i][j]+l[i][k]+l[k][j]);//求答案,当然这里的n改成k也可以AC,只不过时间复杂度不一样罢了
        r(i,1,n)
         r(j,1,n)
          dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);//floyed
     }
    if(ans>=50000000) puts("No solution");else
    printf("%d",ans);//特判
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值