http://acm.hdu.edu.cn/showproblem.php?pid=1598
题意:给定有向图和起点和终点,求从起点到终点的路径中,权重最大和最小的边的最小差。
思路:很好的一道题目。一开始看到图的点数最多为200个的时候想到可以用floyd做,但是后来就发现其实最小差并没有最优子问题的性质,也就是说用dis[i][j]表示i和j之间的最小差,在dis[i][j]取到最优的时候,并不一定是dis[i][k] 和 dis[k][j] 取到最优的时候,因此这里我们并不能用floyd。这里我们可以这样考虑,在每次给定一对起点和终点的时候,因为只有1000条边, 我们可以考虑依次枚举最小的权重, 然后每次添加一条边, 直到起点和终点连通为止,此时由最大边就可以得出一个差值,这样一次枚举所有的可能就可以得出最终的最优解。这里判断图是否连通可以用并查集的方法。
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int INF = 0x3f3f3f3f ;
int N , M ,Q;
struct Node{
int s,e,d ;
}edge[1010] ;
bool comp(Node n1, Node n2){
return n1.d < n2.d;
}
int f[210] ;
void Init(){
for(int i=1;i<=N;i++)
f[i] = i ;
}
int find(int a){
if(a != f[a]){
f[a] = find( f[a] ) ;
}
return f[a] ;
}
void Union(int a, int b){
int fa = find(a) ;
int fb = find(b) ;
if(fa == fb) return ;
if(fa < fb){
f[fb] = fa ;
}
else
f[fa] = fb;
}
int main(){
int a, b,c ;
while(scanf("%d %d",&N,&M) == 2){
for(int i=0;i<M;i++){
scanf("%d %d %d",&a,&b,&c);
edge[i].s = a ;
edge[i].e = b ;
edge[i].d = c ;
}
sort(edge,edge+M,comp);
scanf("%d",&Q);
for(int i=1;i<=Q;i++){
int u ,v ;
int ans = INF ;
scanf("%d %d",&u,&v);
for(int j=0;j<M;j++){
Init() ;
int minlen = edge[j].d ,maxlen;
for(int k=j;k<M;k++){
a = edge[k].s ;
b = edge[k].e ;
c = edge[k].d ;
Union(a,b) ;
if(find(u) == find(v)){
maxlen = edge[k].d ;
if(ans > maxlen - minlen){
ans = maxlen - minlen;
}
break ;
}
}
}
if(ans == INF)
ans = -1 ;
printf("%d\n",ans);
}
}
return 0 ;
}