http://codeforces.com/contest/1343/problem/E
给定一个无向图,n个顶点,m条边,以及长度为m的数组(边权),保证每对顶点之间至少有一条路径;
mike计划从顶点a到顶点b再到顶点c,同一个顶点可以访问多次,每条边有一个边权,问怎样分配边权才能使mike走过的路的边权和最小,重复走过的路重复算。
求最小边权和。
思路:
代码如下:
#include <bits/stdc++.h> using namespace std; const int MAXN=5e5+5; const int mod=1e9+7; typedef long long ll; const int inf=0x3f3f3f3f; const long long INF=0x3f3f3f3f3f3f3f3f; vector<int>g[MAXN]; ll w[MAXN],sum[MAXN]; int d[5][MAXN]; void bfs(int u,int t) { queue<int>q; q.push(u); d[t][u]=0; while(!q.empty()) { int v=q.front(); q.pop(); for(auto to:g[v]) { if(d[t][to]!=-1)continue; d[t][to]=d[t][v]+1; q.push(to); } } } int main() { int t; scanf("%d",&t); while(t--) { int n,m,a,b,c; scanf("%d%d%d%d%d",&n,&m,&a,&b,&c); for(int i=1;i<=m;i++)scanf("%lld",&w[i]); for(int i=1;i<=n+10;i++)d[0][i]=-1,d[1][i]=-1,d[2][i]=-1,sum[i]=0,g[i].clear();//初始化 for(int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); g[v].push_back(u); g[u].push_back(v); } sort(w+1,w+1+m); for(int i=1;i<=m;i++)sum[i]=sum[i-1]+w[i]; bfs(a,0);//a->x bfs(b,1);//x->b || b->x bfs(c,2);//x->c ll ans=INF; for(int i=1;i<=n;i++) { if(d[0][i]+d[1][i]+d[2][i]>m)continue;//超过m时,sum数组越界,前缀和出现问题 ans=min(ans,sum[d[1][i]]+sum[d[0][i]+d[1][i]+d[2][i]]); } printf("%lld\n",ans); } return 0; }