题解:P9377 [THUPC 2023 决赛] 百合
这题确实是好题。
我们记录状态
按照标准的 dijkstra 算法流程,我们从小根堆里面取出对顶,这时候堆顶的状态是
因为我们从当前点到新点之间需要记录不同的
源代码:
#include<bits/stdc++.h>
#define int long long
#define mp make_pair
#define fi first
#define se second
#define lb lower_bound
#define fr front()
#define pii pair<int,int>
#define INF 1145141919810
using namespace std;
int n,m,k,s,dis[200005],a[20];
int vis[200005][18][18];
vector<pii> t[200005];
struct node{
int u,dis;
friend bool operator<(node a,node b){
return a.dis>b.dis;
}
};
struct node2{
int u,i,j;
};
priority_queue<node> q;
queue<node2> qx;
void dijkstra(){
q.push({s,0});
while(!q.empty()){
int u=q.top().u;q.pop();
if(vis[u][0][0])continue;
for(auto i:t[u]){
if(vis[i.fi][0][0])continue;
if(dis[i.fi]>dis[u]+i.se){
dis[i.fi]=dis[u]+i.se;
q.push({i.fi,dis[i.fi]});
}
}
qx.push({u,0,0});
while(!qx.empty()){
int now=qx.fr.u,i=qx.fr.i,j=qx.fr.j;qx.pop();
//cout<<now<<"\n";
vis[now][i][j]=1;
if(i==k){
if(dis[now]>dis[u]+a[j])
dis[now]=dis[u]+a[j],q.push({now,dis[now]});
continue;
}
if(!vis[now][i+1][j])qx.push({now,i+1,j});
if(!vis[now^(1<<i)][i+1][j+1])qx.push({now^(1<<i),i+1,j+1});
}
}
}
signed main(){
ios::sync_with_stdio(false);
cin>>k>>m>>s;n=(1<<k)-1;
for(int i=1;i<=k;i++)cin>>a[i];
for(int i=1;i<=m;i++){
int u,v,c;cin>>u>>v>>c;
t[u].push_back(mp(v,c));
t[v].push_back(mp(u,c));
}
for(int i=0;i<=n;i++)dis[i]=INF;
dis[s]=0;
dijkstra();
for(int i=0;i<=n;i++)cout<<dis[i]<<" ";
}