最开始的时候做过hdu1598,题意就是问一些点对,求一个差值最小构成的公路集合能连通这个点对,开始的时候没有具体想法,感觉上下界存在不确定性,后来就枚举上下界,通过并查集依次往里面加边,确定出此时最小的上界.
今天做到了poj3189,也是一样的原理,给定一堆顺序,要求出顺序最小的边集,能够满足匹配,不小心看到了风神题解上写的二分字样,二分是最大流里面很常见的一个技巧,利用最大流来判定一个问题,利用二分来加速.也就联想到了hdu1598这道题目.二分当然是可以的,枚举了下界之后用二分来判定上界.但是由于网络流的一些特性,每次重新建图之后跑最大流是比较费时的.可不可以也通过类似上面那道题目类似的方法往图中添加边集,每次求出最大流,这样就可以很好地利用原来跑完最大流之后剩下来的残留网络,速度会快很多,加上这道题目里面数据里谷仓比较小.
用这种方法比较顺利的ac了,时间还挺快(不比二分慢),也印证了上面想法还是比较正确的.
所以这种给出一些特征值,求出满足条件的最小特征值之差 的问题,比较通过的想法就是枚举下界,然后通过二分或者是枚举出上界,具体还是需要看题目的数据范围及操作方法.
思路:一开始以为是最短路,用dijkstra写了好几遍,wawa致死,仔细审题一看,发现是要你去求最大速度与最小速度之差最小的路!最大最小之差最小,那么我们就可以联想到贪心的问题了,这题还有个地方在于能到达目的地,那么就是说明要连通给定的起点与终点了,所以我们可以考虑并查集的思想了!
所以本题的大致的思路可以确定为,我们可以对所有边的权值就行排序,然后从0开始对所有的点进行枚举,连通所有的点,看下find(a)是不是等于find(b),等于我们就可以进行拿此时的最大值与最小值作差就可以了!
代码:
#include<cstdio>
#include<algorithm>
using namespace std;
int fa[222];
const int inf=0x3f3f3f3f;
int n,m;
{
int x,y,d;
}s[1111];
return a.d<b.d;
}
return x==fa[x]?x:fa[x]=find(fa[x]);
}
void Union(int x,int y)
{
x=find(x);
y=find(y);
if(x!=y){fa[x]=y;}
}
int min,max,i,j,k;
min=inf;
for(i=0; i<m; i++){
for(j=1; j<=n; j++)fa[j]=j;
for(j=i; j<m; j++){
Union(s[j].x,s[j].y);
if(find(x)==find(y)){//一旦两者联通,两者速度即相减
max=s[j].d-s[i].d;// 两者速度即相减。
if(max<min){
min=max;//取最小的差值。
break;
}
}
}
}
if(min==inf) return -1;
else return min;
}
int main(void){
int i,j,k,l;
int x,y,q;
while(scanf("%d%d",&n,&m)==2){
for(i=0; i<m; i++)
scanf("%d%d%d",&s[i].x,&s[i].y,&s[i].d);
sort(s,s+m,cmp);
scanf("%d",&q);
while(q--){
scanf("%d%d",&x,&y);
printf("%d\n",slove(x,y));
}
}
}