Bzoj3040 dijkstra堆优化+链式前向星
问题描述:
N个点,M条边的有向图,求点1到点N的最短路(保证存在)。
1<=N<=1000000,1<=M<=10000000
input:
第一行两个整数N、M,表示点数和边数。
第二行六个整数T、rxa、rxc、rya、ryc、rp。
前T条边采用如下方式生成:
1.初始化x=y=z=0。
2.重复以下过程T次:
x=(xrxa+rxc)%rp;
y=(yrya+ryc)%rp;
a=min(x%n+1,y%n+1);
b=max(y%n+1,y%n+1);
则有一条从a到b的,长度为1e8-100*a的有向边。
后M-T条边采用读入方式:
接下来M-T行每行三个整数x,y,z,表示一条从x到y长度为z的有向边。
1<=x,y<=N,0<z,rxa,rxc,rya,ryc,rp<2^31
output:
一个整数,表示1~N的最短路。
Sample input:
3 3
0 1 2 3 5 7
1 2 1
1 3 3
2 3 1
Sample output:
2
先介绍一下一种新的存图方式:链式前向星
#include<bits/stdc++.h>
using namespace std;
const int MAXV = ;//图中点的最大值
const int MAXN = ;//图中边的最大值
int head[MAXN];//head[u]就代表u为起点的第一条边在edge数组中的下标
int cnt = 0;//cnt 代表当前的所有边的边数
struct EDGE{
int v;//这条边所指向的顶点
int next;//下一条边在edge数组中的下标 默认是0
int w;//边的权值
};
EDGE edge[MAXN];
Add (int x,int y,int w) {//添加边的操作,x->y 权值为w
edge[++cnt].next = head[x];//逆序添加边,添加的边为head[x]所代表的
edge[cnt].v = y;
edge[cnt].w = w;
head[x] = cnt;
}
void Print(int u) {//遍历操作,从u顶点开始遍历由该顶点出发的所有边
for(int i = head[u];i != 0;i = edge[i].next) {
printf("%d %d
",edge[i].v,edge[i].w);
}
}
这题如果不用链式前向星存的话会爆内存。。。 当然也有神仙通过配对堆优化来卡过内存 总之简单的使用dijkstra堆优化来写的话就会mle(还有牛逼老哥用斐波那契堆优化过的orz hhhhhh)
当然仅仅用链式前向星的话也是没用的,你还会因为你的优先队列入队太多而re掉(呜呜呜呜这什么神仙题卡了我一整天,归根到底还是我太菜了hhhhhh(这题其实前面的T条边实在假你,因为前面的边对最短路根本没有贡献
ac代码如下:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
const int maxm = 1e7 + 5;
const int tt = 1e8;
int n, m, dis[maxn];
int t, rxa, rxc, rya, ryc, rp;
struct edge{
int to, w, next;
} ed[maxm];
int head[maxn], tot;
bool vis[maxn];
inline void add( int u, int v, int w ){
ed[++tot].to = v;
ed[tot].w = w;
ed[tot].next = head[u];
head[u] = tot;
}
inline void dij(int beg){
priority_queue< pair<int, int> > q;
dis[beg] = 0;
q.push(make_pair(0, beg));
while( !q.empty() ){
int u = q.top().second;
q.pop();
if( vis[u] ) continue;
vis[u] = 1;
for( int i=head[u]; i!=0; i=ed[i].next ){
int v = ed[i].to;
if(vis[v]) continue;
if( dis[v]>dis[u]+ed[i].w ){
dis[v] = dis[u]+ed[i].w;
q.push( make_pair(-dis[v], v) );
}
}
}
}
int main(){
memset( vis, 0, sizeof(vis) );
memset( dis, 0x3f, sizeof(dis) );
tot = 1;
scanf("%d%d", &n, &m);
scanf("%d %d %d %d %d %d", &t, &rxa, &rxc, &rya, &ryc, &rp);
for( int i=0; i<t; i++ ){
int x, y, a, b, w;
x = (x*rxa+rxc)%rp;
y = (y*rya+ryc)%rp;
a = min(x%n+1, y%n+1);
b = max(y%n+1, y%n+1);
w = tt-100*a;
add( a, b, w );
}
for( int i=t; i<m; i++ ){
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
add( u, v, w );
}
dij(1);
printf("%d
", dis[n]);
return 0;
}