题解:P9377 [THUPC 2023 决赛] 百合
chenhanzheapple · · 题解
传送门
思路
直接建图显然不行。
这种建完全图的题有一个很典的 trick:建虚点(辅助点)或拆点。
又发现
发现这个东西仍然很难维护,又因为位数很少,不妨按位决策。
设点
建边是显然的。
因为原图中本来就有的边可以互相抵达,所以若
对于点
对于点
对于点
代码中并不需要把这些边建出来。
发现时间复杂度是
发现图中有很多边权为
最终的时间复杂度为
代码
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
int k,m,s;
int a[18],dis[150005];
bool vis[150005],vis2[150005][20][20];
struct node{
int x,w;
bool operator < (const node &b) const{
return b.w<w;
}
};
struct node2{
int x,y,z;
};
vector<node> v[150005];
priority_queue<node> que;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> k >> m >> s;
for(int i=1;i<=k;i++){
cin >> a[i];
}
for(int i=1;i<=m;i++){
int x,y,w;
cin >> x >> y >> w;
v[x].push_back((node){y,w});
v[y].push_back((node){x,w});
}
memset(dis,0x3f,sizeof(dis));
dis[s] = 0;
que.push((node){s,0});
while(!que.empty()){
node t = que.top();
que.pop();
if(vis[t.x]){
continue;
}
vis[t.x] = 1;
for(auto x:v[t.x]){
if(dis[x.x]>dis[t.x]+x.w){
dis[x.x] = dis[t.x]+x.w;
que.push((node){x.x,dis[x.x]});
}
}
queue<node2> q;
q.push((node2){t.x,0,0});
while(!q.empty()){
node2 t2 = q.front();
q.pop();
vis2[t2.x][t2.y][t2.z] = 1;
if(k==t2.y){
if(dis[t2.x]>dis[t.x]+a[t2.z]){
dis[t2.x] = dis[t.x]+a[t2.z];
que.push((node){t2.x,dis[t2.x]});
}
}
else if(t2.y<k){
if(!vis2[t2.x][t2.y+1][t2.z]){
q.push((node2){t2.x,t2.y+1,t2.z});
}
if(!vis2[t2.x^(1<<t2.y)][t2.y+1][t2.z+1]){
q.push((node2){t2.x^(1<<t2.y),t2.y+1,t2.z+1});
}
}
}
}
for(int i=0;i<(1<<k);i++){
cout << dis[i] << " ";
}
return 0;
}