3482: [COCI2013]hiperprostor dijkstra+凸包

Description
在遥远的未来,行星之间的食品运输将依靠单向的贸易路线。每条路径直接连接两个行星,且其运输时间是已知的。贸易商协会打算利用一项最近发现的新技术——超空间旅行,以增加一些新的航线。通过超空间旅行的航线也是单向的。由于该项技术仍处于试验阶段,超空间旅行的时间目前是未知的,但它不取决于行星之间的距离,所以每个超空间旅行的路线将花费等量的时间。下图是三个相互联通的行星及其运输时间的例子。行星使用正整数标号,超空间旅行时间记为“x”(图片对应第输入样例):过境的时间以天计,并且始终是一个正整数。贸易商协会希望对引进新航线的后果进行分析:对于某两个行星A和B,他们想知道对于任意的x,从A到B的最短路径的总中转时间的所有可能的值。例如,在上述情况中,从星球2到星球1的最短路径所需时间可以取值5(如果x≥5),4,3,2,或1天(如果x<5)

题解:

先求出经过1~n条x边的最短路,因为经过大于n条x边的最短路是无意义的。设最短路为y,那么这些最短路可以写成如下形式: y0=b0,y1=x+b1,y2=2x+b2,y3=3x+b3...... y 0 = b 0 , y 1 = x + b 1 , y 2 = 2 x + b 2 , y 3 = 3 x + b 3...... ,那么这就形成了一条条的直线,因为是最短路,所以一定是取最下面的那些,那么也就需要维护一个凸包,最后算一下答案就可以了。

代码:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=510;
const int Maxm=10010;
const int inf=1061109567;
const double eps=1e-8;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='x')return 0;if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    return x*f;
}
int n,m;
struct Edge{int y,d,next;}e[Maxm];
int last[Maxn],len=0;
void ins(int x,int y,int d)
{
    int t=++len;
    e[t].y=y;e[t].d=d;
    e[t].next=last[x];last[x]=t;
}
struct Node
{
    int dis,p,nx;
    Node(int _dis,int _p,int _nx){dis=_dis,p=_p,nx=_nx;}
};
bool operator > (Node a,Node b){return a.dis>b.dis;} 
int f[Maxn][Maxn];
void dijkstra(int start)
{
    priority_queue<Node,vector<Node>,greater<Node> >q;
    q.push(Node(0,start,0));
    memset(f,63,sizeof(f));f[0][start]=0;
    while(!q.empty())
    {
        Node t=q.top();q.pop();
        if(t.dis>f[t.nx][t.p])continue;
        int x=t.p;
        for(int i=last[x];i;i=e[i].next)
        {
            int y=e[i].y;
            if(!e[i].d)
            {
                if(t.nx==n)continue;
                if(f[t.nx][x]<f[t.nx+1][y])
                {
                    f[t.nx+1][y]=f[t.nx][x];
                    q.push(Node(f[t.nx+1][y],y,t.nx+1));
                }
            }
            else
            {
                if(f[t.nx][x]+e[i].d<f[t.nx][y])
                {
                    f[t.nx][y]=f[t.nx][x]+e[i].d;
                    q.push(Node(f[t.nx][y],y,t.nx));
                }
            }
        }
    }
}
struct line{double k,b;}q[Maxn];
double calc(double k1,double b1,double k2,double b2){return (b2-b1)/(k1-k2);}
int main()
{
    n=read(),m=read();
    int cntx=0;
    for(int i=1;i<=m;i++)
    {
        int x=read(),y=read(),d=read();
        ins(x,y,d);cntx+=(!d);
    }
    int Q=read();
    while(Q--)
    {
        int x=read(),y=read();
        dijkstra(x);
        bool flag1=false;
        for(int i=0;i<=n;i++)
        if(f[i][y]!=inf){flag1=true;break;}
        if(!flag1){puts("0 0");continue;}
        if(f[0][y]==inf){puts("inf");continue;}
        int tail=0;
        for(int i=n;i>=0;i--)
        {
            if(f[i][y]==inf)continue;
            while(tail)
            {
                if(tail>1)
                {
                    double x1=calc((double)i,(double)f[i][y],q[tail].k,q[tail].b);
                    double x2=calc(q[tail].k,q[tail].b,q[tail-1].k,q[tail-1].b);
                    if(x1<=x2)tail--;
                    else break;
                }
                else
                {
                    if((double)f[i][y]<=q[tail].b)tail--;
                    break;
                }
            }
            q[++tail].k=(double)i;q[tail].b=(double)f[i][y];
        }
        double lastx=1.0;
        int ans1=0;LL ans2=0;
        for(int i=1;i<tail;i++)
        {
            double x1=0.0,x2;
            x2=calc(q[i].k,q[i].b,q[i+1].k,q[i+1].b);
            double tmp=x2;
            if(lastx>x2)
            {
                if(i==tail-1)
                {
                    ans1++;
                    ans2+=(LL)q[tail].b;
                }
                continue;
            }
            x2=floor(x2);
            ans1+=(int)(x2-lastx+1.0);
            ans2+=(LL)((lastx+x2)*(x2-lastx+1.0)*0.5*q[i].k+(x2-lastx+1.0)*q[i].b);
            if(i==tail-1&&abs(tmp-x2)>eps)
            {
                ans1++;
                ans2+=(LL)q[tail].b;
            }
            lastx=x2+1.0;
        }
        if(tail==1)ans1=1,ans2=q[tail].b;
        printf("%d %lld\n",ans1,ans2);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值