hdu 4725

这个题虽然知道是一个求最短路的题目,但构图好像不太会···,不知道如何把数量那么大的节点带边权表达,所以比赛的时候就没做了,后面再看别人解题报告,才发现其实还是用vector来表达的,不过是一个结构体的vecor,看来stl里面的那些常用函数还是没怎么熟悉,不过我一开始读I题就知道层与层之间是要构成连通的边的,不过当时只是想着需要一个虚拟点,但后来看了别人解题报告发现,一个虚拟点是不够的,因为一个的话会把同一层本来没有连通的点给连通了,好像很多人坑在这里了,所以要设置两个点分别在原来基础上(n+2*i-1)作为入点,(n+2*i)作为本层出点,然后和本层点构成虚拟边权值为0,与相邻层也构成虚拟边权值为c,最后再使用mlogn的用优先队列优化的dijkstra求最短路就可以出解。

看来图论得做些题来加强一下啦,加油。

(由于图论基础不扎实,套了别人的模版···)出自http://www.cnblogs.com/kuangbin/archive/2013/09/11/3315071.html

#include<stdio.h>
#include<vector>
#include<algorithm>
#include<queue>

using namespace std;

const int maxn=1000005;
const int INF=0x3f3f3f3f;
int vis[maxn];
int dis[maxn];

struct edge{
    int v;
    int w;
    edge(int _v,int _w):v(_v),w(_w){}; 
};
 
struct node{
    int U;
    int W;
    //优先级重载函数 
    node(int _U=0,int _W=0):U(_U),W(_W){};
    bool operator < (const node& item) const{
        return W > item.W; //如果当前对象的值大了要调换顺序压入栈底 
    }
};

vector <edge> Edge[maxn];

void addedge(int u,int v,int w){
     Edge[u].push_back(edge(v,w));
}

void dijkstra(int Nnum,int start){
     priority_queue <node> q;
     memset(vis,0,sizeof(vis));
     memset(dis,0x3f,sizeof(dis));
     
     while(!q.empty())q.pop();
     dis[start]=0;
     q.push(node(start,0));
     node tmp;
     while(!q.empty()){
         tmp=q.top();//取出最小的d[i]值 
         q.pop();
         int uu=tmp.U;
         if(vis[uu])continue;
         vis[uu]=1;
         for(int i=0;i<Edge[uu].size();i++){
              int vv=Edge[uu][i].v;//遍历相邻点 
              int ww=Edge[uu][i].w;
              if(!vis[vv]&&dis[vv]>dis[uu]+ww){
                  dis[vv]=dis[uu]+ww;
                  q.push(node(vv,dis[vv]));
              }
         }
     }
    
}

int main(){
     int t,n,m,c,u,v,w;
     scanf("%d",&t);
     for(int kase=1; kase<=t; kase++){ 
          scanf("%d %d %d",&n,&m,&c);
          for(int i=1; i<=3*n; i++)Edge[i].clear();//每次都要把记录先清除 
          for(int i=1; i<=n; i++){//每个节点和自身楼层两个出入点的值应该为0 
               scanf("%d",&u);
               addedge(n+u*2,i,0);
               addedge(i,n+u*2-1,0); 
          }
          
          for(int i=1; i<=m; i++){//将M条边储存 
               scanf("%d %d %d",&u,&v,&w);
               addedge(u,v,w);
               addedge(v,u,w);
          }
          
          for(int i=1; i<n; i++){//把每个楼层的边相连 
               addedge(n+i*2-1,n+(i+1)*2,c);
               addedge(n+(i+1)*2-1,n+i*2,c); 
          } 
           
          dijkstra(3*n,1);
          if(dis[n]==INF)dis[n]=-1;
          printf("Case #%d: %d\n",kase,dis[n]);
     }
     return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值