您的位置:首页 > 其它

[kuangbin带你飞]专题四 最短路练习 P

2016-12-29 09:51 369 查看
http://acm.hdu.edu.cn/showproblem.php?pid=4725

题意:

有n个点 , m条无向边 , 每条边都是有权值 , 并且 , 每个点属于一个楼层 , 相邻楼层之间任意两点可以通过 , 但是要花费 c , 求 1 到 n的最小花费(同楼层没有边的两个点还是不能通过)

tip:

直接相互两边肯定会tle,然后我想每个楼层一个点,同楼层每个点入他出他都是0的边,两个楼层间新加的点连c的边,但是,这样会使同楼层的各个点互达,通过我扩展的点,于是我们可以继续想,每个楼层加两个扩展点,一个让所有点入,一个出,然后出的这个点指向下一层入的扩展点。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
int n,m,c;
typedef pair<int,int>pii;
priority_queue<pii,vector<pii>,greater<pii> >q;
const int maxn = 1e6+10;
const int maxm = 1e6+10;
int head[maxn],tot,dist[maxn];
bool vis[maxn];
struct node{
int v,next,w;
}edges[maxm];
void add(int u,int v,int w){
edges[tot].v=v;edges[tot].w=w;edges[tot].next=head[u];head[u]=tot++;
//edges[tot].v=u;edges[tot].w=w;edges[tot].next=head[v];head[v]=tot++;
}
void init(){
tot = 0;
memset(head,-1,sizeof(head));
memset(vis,false,sizeof(vis));
while(!q.empty())   q.pop();
scanf("%d%d%d",&n,&m,&c);
for(int i = 1 ; i <= n ; i++){
int ce;
scanf("%d",&ce);
add(i,ce*2+n-1,0);
add(ce*2+n,i,0);
}
for(int i = 1; i < n ; i++){
add(n+2*i-1,n+2*(i+1),c);
add(n+2*(i+1)-1,n+2*i,c);
}

for(int i =  0 ; i < m ; i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
}

void dij(){
q.push(make_pair(0,1));
for(int i = 2; i <= 3*n+10 ; i++)
dist[i] = (1<<30);
dist[1] = 0;
while(!q.empty()){
pii tmp = q.top();
// printf("fir = %d\n",tmp.first);
q.pop();
if(vis[tmp.second])  continue;
vis[tmp.second] = true;
for(int k = head[tmp.second];k!=-1;k=edges[k].next){
if(vis[edges[k].v]==false&&dist[edges[k].v] > dist[tmp.second]+edges[k].w){
dist[edges[k].v] = dist[tmp.second]+edges[k].w;
q.push(make_pair(dist[edges[k].v],edges[k].v));
}
}
}
if(dist
== (1<<30))
printf("-1\n");
else
printf("%d\n",dist
);
}
int main(){
int T,ca=1;
scanf("%d",&T);
while(T--){
init();
printf("Case #%d: ",ca++);
dij();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: