HDU 4725 思维建图 Dijkstra 空间换时间

 建完图直接套个Dijkstra+priority的模板就好了,建图一小时,套模板半分钟。

//这题主要难在建图上,要将层抽象出来成为n个点(对应编号依次为n+1~n+n),
//然后层与层建边,点与点建边,层与在该层上的点建边(边长为0),点与相邻层建边(边长为c)。
//ps:这样处理就不用拆点了。不过要注意的是相邻两层必须都要有点才建边(不然会WA,可以参考我贴的数据)。
//然后还有一点要注意的,就是题目隐含条件:同层如没有边是无法直接到达的
//同层的两个点,必须有一个点到达相邻一层,然后再返回本层,曲线救国
//这就要求我们在建立点和边的关系的时候用一个小技巧
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define INF 0x3f3f3f3f
using namespace std;
const int maxe=4000100;
const int maxv=200010;
int cnt;
int dis[maxv],head[maxv];
bool visit[maxv];
struct Edge{
    int to,val,next;
}edge[maxe];
struct Node{
    int u,dis;
    bool operator< (const Node rhs) const{
        return this->dis>rhs.dis;
    }
}now,temp;
void init(){
    memset(head,-1,sizeof head);
    memset(dis,INF,sizeof dis);
    memset(visit,false,sizeof visit);
    cnt=0;
}
void addedge(int from,int to,int val){
    edge[cnt].to=to;
    edge[cnt].val=val;
    edge[cnt].next=head[from];
    head[from]=cnt++;
}
void Dijkstra(int s,int head[],Edge edge[],int dist[],bool visit[]) {
    int i,v;
    dist[s]=0;
    priority_queue<Node> pq;
    temp.dis=0,temp.u=s;
    pq.push(temp);
    while(!pq.empty()) {
        temp=pq.top();
        pq.pop();
        if(visit[temp.u]==true)
            continue;
        visit[temp.u]=true;
        for(i=head[temp.u]; i!=-1; i=edge[i].next) {
            v=edge[i].to;
            if(visit[v]==false&&dist[v]>dist[temp.u]+edge[i].val) {
                dist[v]=dist[temp.u]+edge[i].val;
                now.u=v;
                now.dis=dist[v];
                pq.push(now);
            }
        }
    }
}
int main(void) {
#ifndef ONLINE_JUDGE
    freopen("E:\\input.txt","r",stdin);
#endif // ONLINE_JUDGE
    int kase=0,T,n,m,c;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d%d",&n,&m,&c);
        init();
        int lay[maxv]={0};
        bool visit_lay[maxv]={false};
        for(int i=1;i<=n;i++)
            scanf("%d",&lay[i]),visit_lay[lay[i]]=true;
        for(int i=1;i<n;i++)//层与层建边
            if(visit_lay[i]==true&&visit_lay[i+1]==true)
                addedge(n+i,n+i+1,c),addedge(n+i+1,n+i,c);
        for(int i=1;i<=n;i++){
            addedge(n+lay[i],i,0);
            if(lay[i]>1)//这里必须要用两个if,我第一开始写了个add(i,lay[i]+n,c)
//但是很明显有个问题,就是同一层的两个点,花费代价c就能到达,但是这明显不符合题意的
                addedge(i,n+lay[i]-1,c);
            if(lay[i]<n)
                addedge(i,n+lay[i]+1,c);
        }
        int u,v,w;
        for(int i=1;i<=m;i++)
            scanf("%d%d%d",&u,&v,&w),addedge(u,v,w),addedge(v,u,w);
        Dijkstra(1,head,edge,dis,visit);
        printf("Case #%d: ",++kase);
        if(dis[n]<INF)
            printf("%d\n",dis[n]);
        else
            printf("-1\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/shadandeajian/article/details/81298390