解题思路:这道题我一开始的思路是动规,dp_max[i][j]表示i-j的最大边,dp_min[i][j]表示i-j的最小边,可是这样会有问题,有可能最大边与最小边不在同一条路径上,这样就很麻烦了。
正解:参考了网上的思路,这里其实是最小生成树的变形。由于是最大边与最小边的差最小,可以先把所有边按从小到大排好序,接着就是kruskal的思路了,我们把边从小到大以此加入进去,如果start和end之间有通路,那么就说明找到了一条满足要求的路径了。注意,这里由于最小边暂时是未知的,我们应该还要先去枚举最小边。这道题确实是挺难想的,如果第一次接触的话。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 205; const int inf = 0x7ffffff; struct Edge { int u,v,c; }edge[1005]; int n,m,fa[maxn]; int find(int x) { if(fa[x] == x) return x; return fa[x] = find(fa[x]); } void Union(int x,int y) { int fx = find(x); int fy = find(y); if(fx != fy) fa[fy] = fx; } void init() { for(int i = 1; i <= n; i++) fa[i] = i; } bool cmp(Edge a,Edge b) { return a.c < b.c; } int main() { while(scanf("%d%d",&n,&m)!=EOF) { for(int i = 0; i < m; i++) scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].c); sort(edge,edge+m,cmp); int q; scanf("%d",&q); while(q--) { int ans = inf,tmp; int start,end; scanf("%d%d",&start,&end); for(int i = 0; i < m; i++) { init(); tmp = inf; for(int j = i; j < m; j++) { Union(edge[j].u,edge[j].v); if(find(start) == find(end)) { tmp = edge[j].c - edge[i].c; break; //注意要break,否则tmp值会越来越大 } } ans = min(ans,tmp); } if(ans == inf) ans = -1; printf("%d\n",ans); } } return 0; }
时间: 2024-11-13 10:12:58