这道题数据范围比较大,如果暴力建图肯定T了,需要一点小技巧,本人太渣,看了大牛的博客才懂的。
kuang神
有两种思路
增加2n个点,也就是每层变成两个点。
n+2* i-1->n+2 *(i+1) ,路权为c;即指向上一层
n+2*(i+1)-1->n+2 * i ,路权为c;即指向下一层
如果i属于u层,
则
i->n+2*u-1,路权为零,入层
n+2*u->i,路权为零,出层
再加上m条有向边,建图完成,接着就是最短路,dijkst+堆优化和spfa都可以。
#include
#include
#include
#include
#include
#include
#include
#include
#define msc(X) memset(X,-1,sizeof(X))
#define ms(X) memset(X,0,sizeof(X))
typedef long long LL;
using namespace std;
const int MAXN=1010010;
const int INF=0x3f3f3f3f;
int d[MAXN],tot,hd[MAXN];
bool vs[MAXN];
struct _Edge
{
int to,c,next;
bool operator < (const _Edge &a) const{
return c>a.c;
}
}edge[2*MAXN];
inline void addedge(int u,int v,int c)
{
edge[tot].to=v;
edge[tot].c=c;
edge[tot].next=hd[u];
hd[u]=tot++;
}
void Dijkst(int beg,int n)
{
struct _Edge tmp;
ms(vs);
for(int i=1;i<=n;i++) d[i]=INF;
priority_queue <struct _Edge> q;
while(!q.empty()) q.pop();
tmp.to=beg,tmp.c=0;
d[beg]=0;
q.push(tmp);
while(!q.empty()){
tmp=q.top();
q.pop();
int u=tmp.to;
if(vs[u]) continue;
vs[u]=true;
for(int i=hd[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(!vs[v]&&d[v]>d[u]+edge[i].c)
{tmp.c=d[v]=d[u]+edge[i].c;
tmp.to=v;
q.push(tmp);
}
}
}
}
int main(int argc, char const *argv[])
{
int t,ti=0;
cin>>t;
while(++ti<=t){
int n,m,CT;
msc(hd);
tot=0;
scanf("%d %d %d",&n,&m,&CT);
for(int i=1;i<=n;i++) {
int l;
scanf("%d",&l);
addedge(i,n+2*l-1,0);
addedge(n+2*l,i,0);
addedge(n+2*(i+1)-1,n+2*i,CT);
addedge(n+2*i-1,n+2*(i+1),CT);
}
while(m--){
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
addedge(a,b,c);
addedge(b,a,c);
}
Dijkst(1,3*n);
printf("Case #%d: ",ti );
if(d[n]==INF) puts("-1");
else printf("%d\n",d[n] );
}
return 0;
}
但是,这需要姿势,否则时间复杂度就上去了。
像边一样,建一个邻接表,保存每一层的信息。然后更新每个点的时候也更新一次层上所有的点。
代码?我没写=.=|||