Description
某国计划修建若干高速公路,用来连接国内N个城市,经过一番细致的考察后,政府迁出了M条待建的公路
每条公路用三个整数(x,y,z)来,即城市X与城市Y之间可以修一条高速公路,需要Z的花费。出于节约,政府希望从这些公路出选一些出来修建,使总开支最小。并保证建造后任意两个城市之间都可以直接或间接相连。但往往只考虑费用并不能得到最有价值的方案,例如城市A与城市B之间活动较频繁为了方便这两个城市间交通运输,应修建一条AB间直达的高速公路。于是政府考试将某些公路的建造开支降低 ,使得修筑这条公路后,仍然可以得到一个总开支最低(甚至比原来更低)方案,你的任务就是判断这样的计划可不可行。
每条公路用三个整数(x,y,z)来,即城市X与城市Y之间可以修一条高速公路,需要Z的花费。出于节约,政府希望从这些公路出选一些出来修建,使总开支最小。并保证建造后任意两个城市之间都可以直接或间接相连。但往往只考虑费用并不能得到最有价值的方案,例如城市A与城市B之间活动较频繁为了方便这两个城市间交通运输,应修建一条AB间直达的高速公路。于是政府考试将某些公路的建造开支降低 ,使得修筑这条公路后,仍然可以得到一个总开支最低(甚至比原来更低)方案,你的任务就是判断这样的计划可不可行。
Input
第一行三个整数N,M,Q(1<=N<=10000,N-1<=M<=100000,0接下来M行,每行三个整数(X,Y,Z)描述一条可以建造的公路。
(1y,0<=C<=10000)
最后Q行,每行两个整数i,x(1<=i<=M,0<=x)描述一个修改计划,即要你判断如果 将第i条公路的修建费用降低为x元,第i条公路是否可以修建。
(1y,0<=C<=10000)
最后Q行,每行两个整数i,x(1<=i<=M,0<=x)描述一个修改计划,即要你判断如果 将第i条公路的修建费用降低为x元,第i条公路是否可以修建。
Output
按顺序输出Q行,每行输出"Yes"或"No",Yes表示可以建造,No表示不可能
Sample Input
3 4 3
1 2 10
1 3 6
2 3 4
1 3 7
4 6
1 7
1 5
Sample Output
Yes
No
Yes
HINT
Source
思路:prim。
考虑prim的算法过程:每次加入一个点,并且加入该点的条件是dis[i]是还没加入点的dis[]中最小的。
所以执行prim时,用数组no[]保存某点加入的次序,numm[i]保存第i个加入的点的id
查询边(a,b)时(假设a的加入次序先于b),则枚举no[a]+1 ~ no[b]加入的点的dis[],若存在x<=dis[k],原prim算法过程可被打破,边(a,b)会被选择,
因为该边是当前最佳的边;否则还是原算法过程进行。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <iomanip>
using namespace std;
const int maxd = 1000001;
const int N = 1005;
const int M = 1000001;
int map1[N][N], dis[N], vis[N], no[N], numm[N];
struct Path {
int a, b, c;
} p[M];
void prim(int n) {
int cur;
for (int i = 1; i <= n; i++)
dis[i] = maxd;
memset(vis, 0, sizeof(vis));
cur = 1;
dis[cur] = 0;
vis[cur] = 1;
no[cur] = 1;
numm[1] = cur;
//找n-1轮
for (int i = 2; i <= n; i++) {
//枚举上一次加入的点与各个点的距离,更新最小距离dis[i]
for (int j = 1; j <= n; j++) {
if (vis[j] == 0 && dis[j] > map1[cur][j])
dis[j] = map1[cur][j];
}
//选出最短的边,把该边连接的点加入结果集
int mind = maxd;
for (int j = 1; j <= n; j++) {
if (vis[j] == 0 && dis[j] < mind) {
mind = dis[j];
cur = j;
}
}
vis[cur] = 1;
no[cur] = i;
numm[i] = cur;
}
}
void init(int n) {
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
map1[i][j] = maxd;
}
int main() {
int n, m, q, pi, x;
scanf("%d%d%d", &n, &m, &q);
init(n);
for (int i = 1; i <= m; i++) {
scanf("%d%d%d", &p[i].a, &p[i].b, &p[i].c);
if (map1[p[i].a][p[i].b] > p[i].c)
map1[p[i].a][p[i].b] = map1[p[i].b][p[i].a] = p[i].c;
}
//prim走一遍,保存no[],numm[],dis[]
prim(n);
for (int i = 1; i <= q; i++) {
scanf("%d%d", &pi, &x);
int a = no[p[pi].a], b = no[p[pi].b], flag = 0, bno, sno;
if (a > b) {
bno = a;
sno = b;
} else {
bno = b;
sno = a;
}
//枚举p[pi].a 和 p[pi].b两点之间加入的点
//若x<=dis[],则该边为这轮的最优边,可成为最小生成树中的一边
for (int k = sno + 1; k <= bno; k++) {
if (x <= dis[numm[k]]) {
flag = 1;
break;
}
}
if (flag == 1)
printf("Yes\n");
else
printf("No\n");
}
return 0;
}