2021桂林CCPC K. Tax
题目大意
n个点,m条边,无相连通图。
边有两种属性:其类型c,边权为1
1
到达i
的最短路中,经过类型为的边需要付出的代价为。
需要我们求出到达每个点付出的最小代价。
分析
首先,我们肯定是要求出最短路的。
然后,接下来我们可以发现。如果我们想求一个最短路路径下某一个点的最小代价。
这是一个递推的过程,就是说,他一定是从前面的某个也是在最短路径上的点转移过来的。
是不是发现了什么,分层图。
分层图,按照最短路的距离分层,其特点即为转移的所有关系,都是位于最短路的中相邻的两个点。
接下来我们的dfs
转移时,我们只需层与层之间的点转移即可。满足转移关系的就是,最短路中相邻的两个点。
即我们判断两个点是否在相邻两层,只需要判断其间的边是否是最短路中的即可。是的话则有转移关系。
接下来,我们来看看时间复杂度。
假设每一层有x
个点,相邻层的选择都有x
种。
则时间复杂度为
我们直接取一个对数,则式子变为
我们对式子求导整理后可得
式子在x=e
处取到极值。因为x
为整数,则x=3
时取到极值。
则最大时间复杂度为
最大也就是约等于个
时间给了1.5s,够用了。
Ac_code
#include<bits/stdc++.h>
using namespace std;
const int N = 60,M = N*N,maxn = 10010,INF = 0x3f3f3f3f;
int h[N],e[M],ne[M],c[M],idx;
int w[maxn],dist[N],ans[N],cnt[maxn];
int n,m,sum;
void add(int a,int b,int C)
{
e[idx] = b,ne[idx] = h[a],c[idx] = C,h[a] = idx++;
}
void bfs()
{
memset(dist,0x3f,sizeof dist);
queue<int> q;
q.push(1);
dist[1] = 0;
while(q.size())
{
auto t = q.front();
q.pop();
for(int i=h[t];~i;i=ne[i])
{
int j = e[i];
if(dist[j]>dist[t]+1)
{
dist[j] = dist[t] + 1;
q.push(j);
}
}
}
}
void dfs(int u,int pa)
{
for(int i=h[u];~i;i=ne[i])
{
int j = e[i];
if(j==pa) continue;
if(dist[j]==dist[u]+1)
{
cnt[c[i]]++;
sum += cnt[c[i]]*w[c[i]];
ans[j] = min(ans[j],sum);
dfs(j,u);
sum -= cnt[c[i]]*w[c[i]];
cnt[c[i]]--;
}
}
}
int main()
{
scanf("%d%d",&n,&m);
memset(h,-1,sizeof h);
memset(ans,0x3f,sizeof ans);
for(int i=1;i<=m;i++) scanf("%d",w+i);
for(int i=1;i<=m;i++)
{
int u,v,C;scanf("%d%d%d",&u,&v,&C);
add(u,v,C),add(v,u,C);
}
bfs();
dfs(1,-1);
for(int i=2;i<=n;i++) printf("%d\n",ans[i]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步