NOIP2013 提高组 D1T3
A 国有 n n n 座城市,编号从 1 1 1 到 n n n,城市之间有 m m m 条双向道路。每一条道路对车辆都有重量限制,简称限重。
现在有 q q q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
第一行有两个用一个空格隔开的整数 $ n,m$,表示 A 国有 $ n$ 座城市和 m m m 条道路。
接下来 m m m 行每行三个整数 x , y , z x, y, z x,y,z,每两个整数之间用一个空格隔开,表示从 $x $ 号城市到 $ y $ 号城市有一条限重为 z z z 的道路。
注意: x ≠ y x \neq y x=y,两座城市之间可能有多条道路 。
接下来一行有一个整数 q q q,表示有 q q q 辆货车需要运货。
接下来 q q q 行,每行两个整数 x , y x,y x,y,之间用一个空格隔开,表示一辆货车需要从 x x x 城市运输货物到 y y y 城市,保证 x ≠ y x \neq y x=y
共有 q q q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。
如果货车不能到达目的地,输出 − 1 -1 −1。
4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3
3
-1
3
对于 30 % 30\% 30% 的数据, 1 ≤ n < 1000 1 \le n < 1000 1≤n<1000, 1 ≤ m < 10 , 000 1 \le m < 10,000 1≤m<10,000, 1 ≤ q < 1000 1\le q< 1000 1≤q<1000;
对于 60 % 60\% 60% 的数据, 1 ≤ n < 1000 1 \le n < 1000 1≤n<1000, 1 ≤ m < 5 × 1 0 4 1 \le m < 5\times 10^4 1≤m<5×104, 1 ≤ q < 1000 1 \le q< 1000 1≤q<1000;
对于 100 % 100\% 100% 的数据, 1 ≤ n < 1 0 4 1 \le n < 10^4 1≤n<104, 1 ≤ m < 5 × 1 0 4 1 \le m < 5\times 10^4 1≤m<5×104,$1 \le q< 3\times 10^4 $, 0 ≤ z ≤ 1 0 5 0 \le z \le 10^5 0≤z≤105。
问题转换
设特殊点集合为 S S S,目标函数为: f ( v ) = ∑ s ∈ S dist ( s , v ) f(v) = \sum_{s \in S} \text{dist}(s, v) f(v)=s∈S∑dist(s,v)
其中 dist ( s , v ) \text{dist}(s, v) dist(s,v) 表示节点 s s s 到 v v v 的最短路径距离。需要找到 KaTeX parse error: Expected group after '^' at position 2: v^̲ 使得: v = arg min 1 ≤ v ≤ a f ( v ) v^ = \arg\min_{1 \leq v \leq a} f(v) v=arg1≤v≤aminf(v)
核心算法
使用 SPFA 算法(Shortest Path Faster Algorithm)计算每个特殊点到所有节点的最短路径。
维护全局数组 dp1[] 累加所有特殊点到各节点的距离和: dp1 [ v ] = ∑ s ∈ S dist ( s , v ) \text{dp1}[v] = \sum_{s \in S} \text{dist}(s, v) dp1[v]=s∈S∑dist(s,v)
最终遍历 dp1[] 取最小值: ans = min v ∈ [ 1 , a ] dp1 [ v ] \text{ans} = \min_{v \in [1,a]} \text{dp1}[v] ans=v∈[1,a]mindp1[v]
SPFA 优化
使用队列避免重复松弛,时间复杂度平均 O ( k ⋅ m ) O(k \cdot m) O(k⋅m)( k k k 为常数)。
初始化距离为 0x7fffffff(32 位整数最大值),但实际用 long long 存储。
距离累加
dp1[i] += dp[i] 将每个特殊点的最短路径累加到全局数组。
最终 dp1[i] 表示所有特殊点到节点 i i i 的距离和。
无向图处理
add(x, y, c); // 添加双向边
add(y, x, c);
#include
#define int long long
using namespace std;
const int N=1e6+5;
int dp[N],dp1[N],n,m,a,b,x,y,c,h[N],w[N],to[N],ne[N],tot,num[N];
bool vis[N];
void add(int a,int b,int c)
{
tot++;
ne[tot]=h[a];
h[a]=tot;
to[tot]=b;
w[tot]=c;
}
void spfa(int x)
{
fill(dp+1,dp+1+a,0x7fffffff);
fill(vis+1,vis+1+a,0);
dp[x]=0;
queue<int>q;
q.push(x);
vis[x]=1;
while(!q.empty())
{
int j=q.front();q.pop();vis[j]=0;
for(int i=h[j];i;i=ne[i])
{
int jj=to[i];
if(dp[jj]>dp[j]+w[i])
{
dp[jj]=dp[j]+w[i];
if(!vis[jj])
{
vis[jj]=1;
q.push(jj);
}
}
}
}
// cout<
for(int i=1;i<=a;i++)
dp1[i]+=dp[i];
}
signed main()
{
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
memset(dp1,0,sizeof(dp1));
cin>>n>>a>>m;
for(int i=1;i<=n;i++)
cin>>num[i];
for(int i=1;i<=m;i++)
{
cin>>x>>y>>c;
add(x,y,c);
add(y,x,c);
}
for(int i=1;i<=n;i++)
spfa(num[i]);
// for(int i=1;i<=n;i++)
// cout<
// for(int i=1;i<=a;i++)
// cout<
int ans=1e12;int sf=0;
for(int i=1;i<=a;i++)
{
if(ans>dp1[i])
sf=i;
ans=min(ans,dp1[i]);
}
// cout<
// cout<
// cout<
cout<<ans;
return 0;
}