【GRYZ模拟赛】GRYZ就餐时刻

Description

寒假,大家都回家过年去了,只有GRYZ苦逼的竞赛生们还在学校上课。众所周知,有人的地方就需要有饭,但是食堂的大爷们都回家了,我们只能依靠外卖。已知那是一个非常大的外卖店,有专业的盒饭生产设备,为了保证GRYZ的孩子们每顿饭能吃好吃的饭菜,它们总会将a点生产出的盒饭运往加热处加热后再运往b点装车。这些部门非常的高能,它们有时可以生产盒饭,有时又能变身成装车点(不要问我为什么)。

有些部门之间有专门的传送带连接,店长是个非常珍惜时间的人,他希望盒饭从生产出来到运走所花费的时间尽可能的短,但是店长又是一个超级懒人,所以他把计算的工作交给了你

Input

第一行两个整数nmn表示部门数量,m表示传送带数量。出于方便,1号部门是加热处。

接下来m行,每行三个整数uvw,表示有一条从u部门到v部门的传送带,传送过去需要w个单位时间。注意传送带是单向的。

接下来一个整数q,表示有q次运送。

接下来q行,每行两个数ab,表示这一次要将产品从a部门运送到b部门。

Output

输出q行,每行一个整数,表示这次运送最少需要的时间。若没有传送方案,输出-1

Sample Input

5 5

1 2 3

1 3 5

4 1 7

5 4 1

5 3 1

3

4 2

5 3

2 3

Sample Output

10

13

-1

HINT

30%的数据,n≤100m≤500w=1

60%的数据,n≤100m≤5000

20%的数据,q=1

100%的数据,2≤n≤3000m≤1000002≤a,b≤n

q≤1000001≤u,v≤n1≤w≤10000

有些部门之间可能有多条传送带。

题解

其实写这个题的过程非常坎坷,因为我不会写dij,于是,考试的时候,我先自己造了一个dij,然后出乎意料(hhh)的造错了,于是两天后(就是今天)我又认真的写(zao)了一个,但是又错了,因为我根本就不会dij。。。

然后,我开始的时候犯了这样一个**的错误

    flag[1] = true;
    dist[1] =0;
    for (int i=head[1];i;i=e[i].next)
        dist[e[i].to] = e[i].w;

于是遇到重边重边重边啊重边重边重边就要看rp了。。。因为从1出发的边不一定扫到的最后一条就是最短啊!

实际上应该是这样的。。  (感谢世界上最机智的小敏颜!我爱小敏颜!)

    dist[1] =0;

错就错在,我根本不会写dij!!!

正解:跑两个dij。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXM=100010;
const int MAXN=3010;
int head[MAXN]={0},head2[MAXN]={0};
int dist[MAXN]={0},dist2[MAXN]={0};
bool flag[MAXN]={false},flag2[MAXN]={false};
struct edgenode
{
    int next,to,w;
}e[MAXM],e2[MAXM];
int n,m,q,a,b,u,v,w,cnt=0,cnt2=0;
void ins1(int u,int v,int w)
{
    e[++cnt].to=v; e[cnt].next=head[u]; e[cnt].w=w; head[u] = cnt;
}
void ins2(int u,int v,int w)
{
    e2[++cnt2].to=v; e2[cnt2].next=head2[u]; e2[cnt2].w=w; head2[u] = cnt2;
}
void dij()
{
    memset(dist,127,sizeof(dist));
    dist[1] =0;
    for (int j = 1; j<=n ;j++)
    {
        int minv = 10000000,k;
        for (int i=1;i<=n;i++)
            if (!flag[i] && dist[i]< minv)
            {
                minv=dist[i];
                k=i;
            }
        flag[k] = true;
        for (int i=head[k];i;i=e[i].next)
        {
            int v = e[i].to;
            if (!flag[v])
            {
                if (dist[v] > dist[k]+e[i].w)
                    dist[v] = dist[k]+e[i].w;
            }
        }
    }
}
void dij2()
{
    memset(dist2,127,sizeof(dist2));
    dist2[1] =0;
    for (int j = 1; j<=n ;j++)
    {
        int minv = 10000000,k;
        for (int i=1;i<=n;i++)
            if (!flag2[i] && dist2[i]< minv)
            {
                minv=dist2[i];
                k=i;
            }
        flag2[k] = true;
        for (int i=head2[k];i;i=e2[i].next)
        {
            int v = e2[i].to;
            if (!flag2[v])
            {
                if (dist2[v] > dist2[k]+e2[i].w)
                    dist2[v] = dist2[k]+e2[i].w;
            }
        }
    }
}
int main()
{
    freopen("eat.in","r",stdin);
    freopen("eat.out","w",stdout);
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        ins1(u,v,w);
        ins2(v,u,w);
    }
    dij();
    dij2();
    scanf("%d",&q);
    for (int i=1;i<=q;i++)
    {
        scanf("%d%d",&a,&b);
        if (dist2[a]!=2139062143 && dist[b]!=2139062143)
             printf("%d\n",dist2[a]+dist[b]);
         else printf("-1\n");
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}

 

附上我考试的时候乱造的dij,我觉得挺有纪念意义的。。。

/*还拼错了↓。。。看看我多么认真的写了注释。。(因为造完怕自己看不懂)*/
void dijstra()
{
    int minv = 10000000,mini=0;
    for (int k=1;k<=n;k++)
        if (vis[k])             //k的最短路已经确定 
        {
            for (int i=head[k];i;i=e[i].next)            //可以用k扩展其他点。 
            {
                if (!vis[e[i].to])
                    if (e[i].v < minv)
                    {
                        minv = e[i].v;
                        mini = i;
                    }
            }
        }
    if (mini)
    {
        dist[e[mini].to]=dist[e[mini].from]+e[mini].v;            //所有可行的边扩展完以后找出一个最短 
        vis[e[mini].to] = true;
        dijstra();
    }
}
/*还写得有模有样的。。6死我了!*/ 
非常不好意思的折叠了。。。

 

posted @ 2016-02-23 17:30  mengyue  阅读(193)  评论(0编辑  收藏  举报