描述
有一个n个点的无向正权图G,这个图是连通的,小Y知道这些点两两之间的最短路的长度。
小J想要构造一个新的无向正权图G',使得新图中两两之间的最短路的长度与原图一样,并且边数最少。
输入
第一行一个整数n,表示点的个数。
接下来n行,每行n个整数。第i行第j个整数表示i点到j点的在G中的最短路长度,保证合法。
1<=n<=300,保证图G中最短路长度不超过109。
输出
一个整数表示新图G'的最小的边数。
4 0 1 3 6 1 0 2 5 3 2 0 3 6 5 3 0
3
思路:依次求每一个顶点的最短路径图,假设从该顶点出发的距离小于等于其它边之和,则标记它。
#include<iostream> #include<cstdio> #define INF 100000000 using namespace std; int main() { int n; cin >> n; int Map[305][305]; int dis[305][305]; bool flag1[305][305];//判断i点到j点是否被存入 bool flag2[305][305];//判断边ij是否被去除 for(int i=1;i<=n;i++) for (int j = 1; j <= n; j++) { cin >> Map[i][j]; dis[i][j]=Map[i][j]; flag2[i][j]=flag1[i][j] =false; } for (int i = 1; i <= n; i++) { int t = n-1; //最短路径算法Dijkstra while (t--) { int min = INF; int temp; for (int j = 1; j <= n; j++) if (i!=j&&!flag1[i][j] &&dis[i][j] < min) { min = dis[i][j]; temp = j; } flag1[i][temp] = true; for (int j = 1; j <= n; j++) { if (i!=j&&!flag1[i][j] && dis[i][j]>= dis[i][temp] + Map[temp][j]) { dis[i][j] = dis[i][temp] + Map[temp][j]; flag2[i][j] = true; } } } } int e = n*(n - 1) / 2;//总的边数 int cnt = 0; for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) if (flag2[i][j]) cnt++; e = e-cnt / 2; cout << e << endl; return 0; }