hihoCoder #1379 Emulator
hihoCoder Challenge 23, Prob. A
时间限制:5000ms
单点时限:1000ms
内存限制:256MB
描述
有一个\(n\)个点的无向正权图\(G\),这个图是连通的,小Y知道这些点两两之间的最短路的长度。
小J想要构造一个新的无向正权图\(G'\),使得新图中两两之间的最短路的长度与原图一样,并且边数最少。
输入
第一行一个整数\(n\),表示点的个数。
接下来\(n\)行,每行\(n\)个整数。第\(i\)行第\(j\)个整数表示\(i\)点到\(j\)点的在\(G\)中的最短路长度,保证合法。
\(1\le n \le 300\),保证图\(G\)中最短路长度不超过\(10^9\)。
输出
一个整数表示新图\(G'\)的最小的边数。
样例输入
4
0 1 3 6
1 0 2 5
3 2 0 3
6 5 3 0
样例输出
3
Solution
这道题现场卡住了.
首先由题目描述可知原图\(G\)是连通图.
设\(G=G(V,E)\), 现在不知道边集\(E\), 只知道最短路矩阵\(D\).
先考虑一个简化问题:
对于某条给定的边\((u,v)\), 能否从最短路矩阵判断它是否必需 ("必需"即一定存在于原图中), 如果能, 如何判断?
能. 判断方法: 判断是否 \(\exists x \in V \setminus\) \(\{u, v\}\)使得\(D_{u,v}=D_{u,x}+D_{x,v}\).
证明:
\(\forall (u,v) \in E\), 用\(w(u,v)\)表示边\((u,v)\)的长度. 显然\(w(u,v) \ge D_{u,v}\). 又依题意, \(\forall (u,v), \ w(u,v)>0\).
\(D_{u,v}=D_{u,x}+D_{x,v}\) \(\Longrightarrow w(u,v) < D_{u,x}, \ w(u, v) < D_{x, v}\).
\(\Longrightarrow u \to x, \ x \to v\) 的最短路都一定不包含边 \((u,v)\). (这好像很显然:))
这样就可以放心地将边\((u,v)\)从图\(G\)中删除, 而最短路矩阵不变.
这样就可以得出一个迭代的算法. 而且可以推出:
对于给定的最短路矩阵\(D\), 与之对应的边数最少的图是唯一的.
思维链条:
某条边\((u,v)\)是否必需由最短路矩阵\(D\)唯一确定 \(\to\) 删去非必需的边后最短路矩阵\(D\)不变 \(\to\) 删掉的边是"独立"的, 互不影响.
删边的独立性直白地说即是:只有当图\(G\)中存在一条能替代\((u,v)\)这条边的路径时才把\((u,v)\)删除。
Implementation
#include <bits/stdc++.h>
using namespace std;
const int N=305;
int d[N][N];
int main(){
int n;
cin>>n;
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
cin>>d[i][j];
int res=n*(n-1)/2;
for(int i=0; i<n; i++)
for(int j=i+1; j<n; j++){
for(int k=0; k<n; k++){
if(k!=i && k!=j && d[i][j]==d[i][k]+d[k][j]){
--res;
break;
}
}
}
cout<<res<<endl;
return 0;
}