dijkstra模板+ 缩点-bupt新oj-187- Find the Fastest Server


先放一下dijkstra的模板。

不要问我为什么最短路这么基础的东西都要用模板!!!因为我图论弱啊!


typedef pair<int, int> P;

int V;
int d[SIZE_D];

void dijkstra(int s)
{
    V = N;
    priority_queue<P,vector<P>,greater<P> > que;
    //fill(d,d + V, INF);
    //为何楼上的fill没有用啊
    memset(d,-1,sizeof(d));//第一次修改
    d[s] = 0;
    que.push(P(0,s));
    while (!que.empty()){
        P p = que.top();que.pop();
        int ver = p.second;
        if (d[ver] != -1 && d[ver] < p.first) continue;//第二次修改
        for (int i = head[ver]; i != -1; i = pra[i].next){
            int u = pra[i].to, cost = pra[i].w;
            if (ser[u] != 0) continue;
            if (d[u] == -1 || d[u] > d[ver] + cost){
                d[u] = d[ver] + cost;
                que.push(P(d[u],u));//第五次修改
            }
        }
    }
}
//无法到达的点d是-1


题目链接:http://code.bupt.edu.cn/problem/p/187/

讲一下这道题目的题意

题意:有10^4个点,10^5条边,每条边有一个延时,告诉你10^3个服务站。给你10^4个查询点,问每个查询点到最快能到的服务站的延时是多少。注意:一共有40组样例!!!


解答:

1、我一开始用每输入一个服务站就bfs更新所有点的最小距离d【i】的方法,我算了复杂度是10^3 × 10^ 4 大约10的七次方,时限一秒可以过,但是有40组样例啊!10的8次方啊!

2、然后是用二分算一个距离,bfs看看在这个距离里面有没有服务站,有就跳出来,复杂度我不懂算啊!因为bfs随时可以跳出啊!但我觉得比方法一快啊!可是结果比方法一慢了一倍啊!

3、最后就是正解啦!

因为这道题里面,server没有区别,所以可以缩成一个点。这是一个好思路啊!

无差别的点可以缩成一个点啊!!!!!

然后跑一遍dijkstra。把这个超级点作为起点,记录d【i】,然后每次查询就是O(1)的了。

还可以用spfa一试,待会试试看,再来贴代码。

4、还有一件事情啊!那个样例输出是错的啊!!!

不过刚刚让田田把样例改对了。我应该早点跟他说的,刚刚交代码每次都交两遍,wa的次数要除以2了。不过现在的样例是对的了真是造福后人啊!

5、不知道为什么我用fill函数不能把数组变成INF.我查了一下http://www.cplusplus.com/reference/algorithm/fill/ 明明就是在头文件algorithm里面的啊!


粗心的傻逼错:

1、无向图啊!双向边啊!

2、图可能不连通啊!要输出-1啊!!!

3、变量居然打错了orz简直傻逼。。。


放一下dijkstra的代码

#include<bits/stdc++.h>
#define SIZE_D 20005
#define SIZE_B 500005
#define INF 0x3f3f3f3f
using namespace std;
int N,M;
int e,head[SIZE_D];
struct pp
{
    int to,w,next;
}pra[SIZE_B];
void init()
{
    e = 0;
    memset(head,-1,sizeof(head));
}
int addedge(int x,int y,int z)
{
    pra[e].to = y;
    pra[e].w = z;
    pra[e].next = head[x];
    head[x] = e++;
}


bool ser[SIZE_D];

typedef pair<int, int> P;

int V;
int d[SIZE_D];

void dijkstra(int s)
{
    V = N;
    priority_queue<P,vector<P>,greater<P> > que;
    //fill(d,d + V, INF);
    //为何楼上的fill没有用啊
    memset(d,-1,sizeof(d));//第一次修改
    d[s] = 0;
    que.push(P(0,s));
    while (!que.empty()){
        P p = que.top();que.pop();
        int ver = p.second;
        if (d[ver] != -1 && d[ver] < p.first) continue;//第二次修改
        for (int i = head[ver]; i != -1; i = pra[i].next){
            int u = pra[i].to, cost = pra[i].w;
            if (ser[u] != 0) continue;
            if (d[u] == -1 || d[u] > d[ver] + cost){
                d[u] = d[ver] + cost;
                que.push(P(d[u],u));//第五次修改
            }
        }
    }
}
//无法到达的点d是-1


void copyc(int oldd,int newd)
{
    for (int i = head[oldd]; i != -1; i = pra[i].next){
        addedge(newd,pra[i].to,pra[i].w);
        addedge(pra[i].to,newd,pra[i].w);//第三次修改
    }
}
int main()
{
    //freopen("input.txt","r",stdin);
    int T;
    scanf("%d",&T);
    while (T--){
        init();
        scanf("%d %d",&N,&M);
        for (int i = 0; i < M; i++){
            int temp1,temp2,temp3;
            scanf("%d %d %d",&temp1,&temp2,&temp3);
            addedge(temp1,temp2,temp3);
            addedge(temp2,temp1,temp3);
        }
        int k;
        scanf("%d",&k);
        memset(ser,0, sizeof(ser));
        int super;
        for (int i = 1; i <= k; i++){
            int tempv;
            scanf("%d",&tempv);
            ser[tempv] = 1;
            if (i == 1)
                super = tempv;
            else
                copyc(tempv,super);
        }
        dijkstra(super);
        int Q;
        scanf("%d",&Q);
        for (int i = 0; i < Q; i++){
            int tempq;
            scanf("%d",&tempq);
            if (ser[tempq] == 1 ){
                puts("0");
            }else{
                printf("%d\n",d[tempq]);
            }
        }
        puts("");
    }
    return 0;

}


















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值