UVALive - 4618 Wormholes(负环)

31 篇文章 0 订阅
23 篇文章 0 订阅

自己用SPFA做,T了。刚开始还不相信,N<=50,(井底之蛙的集中体现).看了大牛博客看了很久,我做题思路基本上是剽窃的。
大牛博客链接 http://blog.csdn.net/L123012013048/article/details/47820453
这道题主要是要处理负环,但这个负环很特殊,跑着跑着负环就没了。
eg. 本来的负环的某个虫洞的到达时间小于虫洞的生成时间,那么负环就消失了
我之前为什么用spfa超时,就是有可能存在这种负环且消失时间很久,比如每跑一次负环时间-1,但负环中的虫洞的生成时间最晚是-99999(一个很小的数就对了),如果现在时间是0,那要跑这个负环接近99999次负环才会消失。
但是,其实可以发现负环的时候就把他消灭掉。因为负环内的点满足的最优情况就是某个点到达时间刚好等于生成时间(其他点<=)
这样就可以求出这个负环内的能节省的最多时间,然后将所有点都减去那个时间,那么负环就消失了

/*
把开始点和结束点看作穿越时间为0,建的时间是-INF的虫洞
每次计算dis[i][j]表示从i虫洞的出口到j虫洞入口的距离
(这道题距离可以说就是时间)
d[i]表示开始点虫洞的入口到i虫洞的出口的时间
max(dt[i]+dis[i][j],wom[j].t)+wom[j].d就是当前i虫洞的出口转移到j虫洞的出口的时间。(注意:如果j虫洞还没建成,可以等它建成)

找出更新的值,破除这个负环,更新的值就是到达起点的值和生成时间的差的最小值,因为在负环内可以等待到生成时间(太渣,没能想到这一点)
*/
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <stack>
#include <vector>
#include <math.h>
#include <string.h>
#include <queue>
#define msc(X) memset(X,-1,sizeof(X))
#define ms(X) memset(X,0,sizeof(X))
#define mpow(X) ((X)*(X))
typedef long long LL;
using namespace std;
const int MAXN=60;
const int INF=0x3f3f3f3f;
struct _Point
{
    int x,y,z;
};
struct _Wom
{
    struct _Point in,ot;
    int t,d;
}wom[MAXN];
int dis[MAXN][MAXN];
int dt[MAXN],pre[MAXN];
inline int dist(int u,int v)
{return ceil(sqrt((double)(mpow(wom[u].ot.x-wom[v].in.x)+
    mpow(wom[u].ot.y-wom[v].in.y)+mpow(wom[u].ot.z-wom[v].in.z))));}
void Bellman(int beg,int n)
{
    for(int i=0;i<=n;i++) dt[i]=INF;
    dt[beg]=0;
    msc(pre);
    while(1){
        bool flg=false;
        for(int i=0;i<=n;i++)
            for(int j=0;j<=n;j++)
            {
                int nt=max(dt[i]+dis[i][j],wom[j].t)+wom[j].d;
                if(dt[j]>nt)
                    dt[j]=nt,pre[j]=i,flg=true;
            }
        if(!flg) {printf("%d\n",dt[n] );return;}
        for(int i=0;i<=n;i++)
        {
            int k=i;
            for(int j=0;k!=-1&&j<=n;j++) k=pre[k];
            if(k==-1) continue;
            int Mic=dt[pre[k]]+dis[pre[k]][k]-wom[k].t;
            for(int p=pre[k];p!=k;p=pre[p])
                Mic=min(Mic,dt[pre[p]]+dis[pre[p]][p]-wom[p].t);
            if(Mic<=0) continue;
            dt[k]-=Mic;
            for(int p=pre[k];p!=k;p=pre[p])
                dt[p]-=Mic;
        }
    }
}
int main(int argc, char const *argv[])
{
    int c;
    cin>>c;
    while(c--){
        int n;
        struct _Point tmp;
        scanf("%d %d %d",&tmp.x,&tmp.y,&tmp.z);
        wom[0].in=wom[0].ot=tmp,wom[0].t=-INF,wom[0].d=0;
        scanf("%d %d %d%d",&tmp.x,&tmp.y,&tmp.z,&n);
        n++;
        wom[n].in=wom[n].ot=tmp,wom[n].t=-INF,wom[n].d=0;
        for(int i=1;i<n;i++)
        {
            scanf("%d %d %d",&tmp.x,&tmp.y,&tmp.z);
            wom[i].in=tmp;
            scanf("%d %d %d",&tmp.x,&tmp.y,&tmp.z);
            wom[i].ot=tmp;
            scanf("%d %d",&wom[i].t,&wom[i].d);
        }
        for(int i=0;i<=n;i++)
            for(int j=0;j<=n;j++)
                dis[i][j]=dist(i,j);
        Bellman(0,n);
    }
    return 0;
}
/*
2
0 0 0 100 0 0
2
1 1 0 1 2 0 -100 -2
0 1 0 100 1 0 -150 10
0 0 0 10 0 0
1
5 0 0 -5 0 0 0 0
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值