P4568 [JLOI2011] 飞行路线 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
//////////////////////////////////////////////////////法一:分层图
int n,m,k;
int s,t;
const int inf=0x3f3f3f3f;
vector<pair<int,int>> vct[10004*12]; //开多层,一定要开大点!!10004*11都是RE的
priority_queue<pair<int,int>> pq;
int dis[10004*12],vis[10004*12];
void dijkstr(int s){
memset(dis,inf,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[s]=0;
pq.emplace(0,s);
while(pq.size()){
int from=pq.top().second;
pq.pop();
if(vis[from]) continue;
vis[from]=1;
for(auto v:vct[from]){
int to=v.first,weight=v.second;
if(dis[to]>dis[from]+weight){
dis[to]=dis[from]+weight;
pq.emplace(-dis[to],to);
}
}
}
}
void solve(){
cin>>n>>m>>k;
cin>>s>>t;
for(int i=1;i<=m;i++){
int u,v,w; cin>>u>>v>>w;
for(int j=0;j<=k;j++){ //重边不必处理--key:j=[0,k]--到k是因为k的本层要建图,但是k不需要连向k+1层,连了也没wa。
vct[u+j*n].emplace_back(v+j*n,w); //本层是双向的
vct[v+j*n].emplace_back(u+j*n,w);
if(j!=k) vct[u+j*n].emplace_back(v+(j+1)*n,0); //下层的单向的
if(j!=k) vct[v+j*n].emplace_back(u+(j+1)*n,0);
}
}
dijkstr(s);
int ans=INT_MAX;
for(int i=0;i<=k;i++)
ans=min(ans,dis[t+i*n]);
cout<<ans;
}
////////////////////////////////////////////////////法二:dp
int n,m,k;
int s,t;
typedef struct myp{
int d,node;
int t;
friend bool operator < (const myp a,const myp b){
return a.d>b.d; //大于号才是!!小根堆!!!
}
}myp;
const int inf=0x3f3f3f3f;
vector<pair<int,int>> vct[10004];
priority_queue<myp> pq;
int dis[10004][15],vis[10004][15];
void dijkstr(int s){
memset(dis,inf,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[s][0]=0;
pq.emplace((myp){0,s,0});
while(pq.size()){
int from=pq.top().node;
int take=pq.top().t;
pq.pop();
if(vis[from][take]) continue;
vis[from][take]=1;
for(auto v:vct[from]){
int to=v.first,weight=v.second;
if(take+1<=k){
if(dis[to][take+1]>dis[from][take]){
dis[to][take+1]=dis[from][take];
pq.emplace((myp){dis[to][take+1],to,take+1});
}
}
if(dis[to][take]>dis[from][take]+weight){
dis[to][take]=dis[from][take]+weight;
pq.emplace((myp){dis[to][take],to,take});
}
}
}
}
void solve(){
cin>>n>>m>>k;
cin>>s>>t;
for(int i=1;i<=m;i++){
int u,v,w; cin>>u>>v>>w;
vct[u].emplace_back(v,w);
vct[v].emplace_back(u,w);
}
dijkstr(s);
int ans=INT_MAX;
//hack数据--不能单纯输出dis[t][k],类似限高杆,不一定用完免费的会更值当!!!所以要在[0,k]中取最小值。
//k>m0,m0为s到t需要最少的边,如果要用完k,可能会导致跑多余的路程.
for(int i=0;i<=k;i++) ans=min(ans,dis[t][i]);
cout<<ans;
}
P8724 [蓝桥杯 2020 省 AB3] 限高杆 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
////////////////////////////////////////////法一:分层图
int n,m;
const int inf=0x3f3f3f3f;
vector<pair<int,int>> vct[30004];
priority_queue<pair<int,int>> pq;
int dis[30004],vis[30004];
void dijkstr(int s){
memset(dis,inf,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[s]=0;
pq.emplace(0,s);
while(pq.size()){
int from=pq.top().second;
pq.pop();
if(vis[from]) continue;
vis[from]=1;
for(auto v:vct[from]){
int to=v.first,weight=v.second;
if(dis[to]>dis[from]+weight){
dis[to]=dis[from]+weight;
pq.emplace(-dis[to],to);
}
}
}
}
void solve(){
cin>>n>>m;
for(int i=1;i<=m;i++){
int u,v,w,c; cin>>u>>v>>w>>c;
//用以下方式建一个立体的三层图,跑正常的dijkstra即可。恢复一条边的最短距离为dis[2*n];恢复两条边的最短距离为dis[3*n];
//此题恢复的边一定会用上那条边,不一定恢复两条边会比恢复一条边短,或比不恢复边短。取min即可。
if(c==0){ //没有障碍,三层都在本层正常建边
vct[u].emplace_back(v,w); //第一层
vct[v].emplace_back(u,w);
vct[u+n].emplace_back(v+n,w); //第二层
vct[v+n].emplace_back(u+n,w);
vct[u+2*n].emplace_back(v+2*n,w); //第三层
vct[v+2*n].emplace_back(u+2*n,w);
}
else{ //有障碍,第一层连向第二层,第二层连向第三层。
// vct[u].emplace_back(v+n,w); //这4行是错的。
// vct[v+n].emplace_back(u,w);
// vct[u+n].emplace_back(v+2*n,w);
// vct[v+2*n].emplace_back(u+n,w);
vct[u].emplace_back(v+n,w); //单向的!!一层向下一层!!,否则可能会从下层更新上层的点
vct[v].emplace_back(u+n,w);
vct[u+n].emplace_back(v+2*n,w);
vct[v+n].emplace_back(u+2*n,w);
}
}
dijkstr(1);
cout<<dis[n]-min({dis[n],dis[2*n],dis[3*n]}); //不一定恢复的边越多越短!直接取三个的最小值准没错!!
}
/////////////////////////////////////////////////法二:dp
int n,m;
typedef struct myp1{
int v,w,typ;
}myp1;
typedef struct myp2{
int d,node,take;
friend bool operator <(const myp2 a,const myp2 b){ //只能重载小于号!!
return a.d>b.d; //按d的从小到大排序
}
}mpy2;
const int inf=0x3f3f3f3f;
vector<myp1> vct[10004];
priority_queue<myp2> pq;
//priority_queue<pair<int,pair<int,int>>> pq;
int dis[10004][3],vis[10004][3]; //dis[i][j]:已经用了j次免费机会的情况下,到达i的最小距离
void dijkstra(int s){
memset(dis,inf,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[s][0]=0;
pq.emplace((myp2){0,s,0});
while(pq.size()){
int from=pq.top().node;
int take=pq.top().take;
pq.pop();
if(vis[from][take]) continue;
vis[from][take]=1;
for(auto v:vct[from]){
int to=v.v,weight=v.w,typ=v.typ;
if(take+typ>2) continue;
if(dis[to][take+typ]>dis[from][take]+weight){ //dis[to][take+typ] 从 dis[from][take]+weight转移!!
dis[to][take+typ]=dis[from][take]+weight;
pq.emplace(myp2{dis[to][take+typ],to,take+typ});
}
}
}
}
void solve(){ //不建分层图,用动态规划思想.
cin>>n>>m;
for(int i=1;i<=m;i++){
int u,v,w,t; cin>>u>>v>>w>>t;
vct[u].emplace_back((myp1){v,w,t});
vct[v].emplace_back((myp1){u,w,t});
}
dijkstra(1);
cout<<dis[n][0]-min({dis[n][0],dis[n][1],dis[n][2]}); //不一定恢复的边越多越短!直接取三个的最小值准没错!!
}
ps:似乎分层图都可以用dp来做。
标签:pq,emplace,int,练习,分层,vct,take,dis From: https://www.cnblogs.com/ouhq/p/18153876