POJ3268—Silver Cow Party(反向最短路)

题目大意:有编号为1-N的牛,它们之间存在一些单向的路径。给定一头牛的编号,其他牛要去拜访它并且拜访完之后要返回自己原来的位置,求这些牛中所花的最长的来回时间是多少(最短的最长)?


解题思路:一开始以为最短路没有难题,抱着水水的心态来做这个专题,没想到立刻就给我颜色看了。

   这道题我没有多想,拿到题目我就准备dijsktra套模板,从X做一次单源最短路(无终点),然后再从1~NX除外)做一次单源最短路(有终点,遇到X停止),然后把来回和不断与全局变量ans比较,最后得到结果。方法无误,但是时间复杂度我就呵呵了。

  然后我自以为脑洞大开,想到全源最短路Folyd。好吧,直接全源,然后将dis[x][i]+dis[i][x]与ans比较,最后得出结果。然后,考虑时间复杂度,我也呵呵了。

 最后TLE了好久,没忍住,才去看了题解。看完第一句话我就傻了,先从X开始做一次单源最短路,这是去所花的最短时间。然后因为这是个有向图,把边的方向换一下,再做一次从X开始的单源最短路,这就是回所花的最短时间。两组数据加起来,与全局变量ans比较,最后得出结果。对比时间复杂度,这种方法的时间复杂度是常数级的dijsktra。唉,淡淡的忧桑,我的ACM还有希望吗~~~


代码:因为本人的代码能力实在有限,所以就不搞什么高大上了,直接dijsktra复制一遍上,求轻喷

#include <set>
#include <map>
#include <list>
#include <queue>
#include <stack>
#include <cmath>
#include <string>
#include <cstdio>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
#define PB push_back
#define FOR(i,n,m) for(int i=n;i<=m;i++)
#define ROF(i,n,m) for(int i=n;i>=m;i--)
#define clr(i,j) memset(i,j,sizeof(i))
#define maxn  1005
typedef long long ll;
typedef pair<int,int> pii;
const int inf = 0x3f3f3f3f;
int n;
struct edge
{
    int to,dis;
} t;
vector<edge>p[maxn];
vector<edge>q[maxn];
bool vis[maxn];
int dis[maxn];
int dic[maxn];
int dijsktra(int s,int e)
{
    clr(vis,false);
    clr(dis,inf);
    dis[s]=0;
    while(1)
    {
        int x=0,mi=inf;
        for(int i=1; i<=n; i++)
            if(!vis[i]&&dis[i]<mi)
            {
                x=i;
                mi=dis[i];
            }
        if(x==0) return-1;
        if(x==e) return dis[e];
        vis[x]=true;
        for(int i=0; i<p[x].size(); i++)
        {
            int y=p[x][i].to,xy=p[x][i].dis;
            if(!vis[y]&&dis[y]>dis[x]+xy)
                dis[y]=dis[x]+xy;
        }
    }
}
int dijsktra1(int s,int e)
{
    clr(vis,false);
    clr(dic,inf);
    dic[s]=0;
    while(1)
    {
        int x=0,mi=inf;
        for(int i=1; i<=n; i++)
            if(!vis[i]&&dic[i]<mi)
            {
                x=i;
                mi=dic[i];
            }
        if(x==0)return-1;
        if(x==e)return dic[e];
        vis[x]=true;
        for(int i=0; i<q[x].size(); i++)
        {
            int y=q[x][i].to,xy=q[x][i].dis;
            if(!vis[y]&&dic[y]>dic[x]+xy)
                dic[y]=dic[x]+xy;
        }
    }
}
int main()
{
    int m,x;
    while(~scanf("%d %d %d",&n,&m,&x))
    {
        for(int i=1; i<=n; i++)
            p[i].clear(),q[i].clear();
        while(m--)
        {
            int a,b;
            scanf("%d %d %d",&a,&b,&t.dis);
            t.to=b;
            p[a].PB(t);
            t.to=a;
            q[b].PB(t);
        }
        dijsktra(x,0);
        dijsktra1(x,0);
        int ans=0;
        for(int i=1; i<=n; i++)
            if(dis[i]!=inf&&dic[i]!=inf)
                ans=max(ans,dis[i]+dic[i]);
        printf("%d\n",ans);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值