CF1486E Paired Payment

CommonDigger

2024-11-16 21:37:06

Solution

题目大意

CF1486E Paired Payment

单源最短路,但是距离计算的规则是每两条边权值之和的平方,两两一组。例如:分别走过 5,3,11,6 四条边,权值有两组,距离计算是 (5+3)^2+(11+6)^2=353

做法

考虑类似分层图的思想。题目有一个很友善的数据范围:边权 w\le50。所以可以设数组 \texttt{dis[200005][51]},其中 \texttt{dis[i][j]} 表示走到 i 号点,上一条边的边权是 j 的最短路程。特别地,j=0 时,表示接下来是一组新的边。

$j=0$ 时,此时上一条边已经在前面的组合里了,随便选一条边作为新的组合,先不更新权值。 其他的和最短路差别不大,具体见代码。 ## 代码 ```cpp /* Luogu CF1486E Paired Payment https://www.luogu.com.cn/problem/CF1486E */ #include "iostream" #include "queue" #include "cstring" using namespace std; const int N=200005; int n, m, head[N], idx, temp1, temp2, temp3; int dis[N][51]; bool ins[N][51]; struct edge{ int to, nxt, w; }e[2*N]; struct node{ int id, pre; node(int id=1, int pre=0){ this->id=id; this->pre=pre; } }; void add_edge(int u, int v, int w){ e[++idx].to=v; e[idx].w=w; e[idx].nxt=head[u]; head[u]=idx; } int square(int i){ return i*i; } void spfa(){ queue<node>q; q.push(node(1, 0)); memset(dis, 0x3f, sizeof(dis)); dis[1][0]=0; while(!q.empty()){ int id=q.front().id, pre=q.front().pre; ins[id][pre]=false; q.pop(); if(pre==0){ for(int i=head[id];i;i=e[i].nxt){ int to=e[i].to, w=e[i].w; if(dis[id][0] < dis[to][w]){ dis[to][w] = dis[id][0]; if(!ins[to][w]){ ins[to][w]=true; q.push(node(to, w)); } } } }else{ for(int i=head[id];i;i=e[i].nxt){ int to=e[i].to, w=e[i].w; if(dis[id][pre]+square(pre+w)<dis[to][0]){ dis[to][0]=dis[id][pre]+square(pre+w); if(!ins[to][0]){ ins[to][0]=true; q.push(node(to, 0)); } } } } } } int main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin >> n >> m; for(int i=1;i<=m;i++){ cin >> temp1 >> temp2 >> temp3; add_edge(temp1, temp2, temp3); add_edge(temp2, temp1, temp3); } spfa(); for(int i=1;i<=n;i++) cout << (dis[i][0]==0x3f3f3f3f ? -1 : dis[i][0]) << " "; } ```