题目链接:https://www.luogu.com.cn/problem/P1396
注意要用双向边!!
1.二分+DFS:
二分路径最大值,然后DFS,如果边权小于mid,那么可以走,否则不可以走。DFS只需要判断s->t是否连通:跑一边DFS,然后用vis看能否连通。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 using namespace std; 5 const int N=20005; 6 int n,m,s,t; 7 int head[N],tot,dis[N],vis[N]; 8 struct node{ 9 int to,next,w; 10 }edge[N<<1]; 11 void add(int u,int v,int w){ 12 edge[tot].to=v; 13 edge[tot].next=head[u]; 14 edge[tot].w=w; 15 head[u]=tot++; 16 } 17 void check(int u,int x){ 18 vis[u]=1; 19 for(int i=head[u];i!=-1;i=edge[i].next){ 20 int v=edge[i].to; 21 if(vis[v]) continue; 22 if(edge[i].w<=x){ 23 check(v,x); 24 } 25 } 26 } 27 int main(){ 28 memset(head,-1,sizeof(head)); 29 scanf("%d%d%d%d",&n,&m,&s,&t); 30 for(int i=1;i<=m;i++){ 31 int u,v,w; 32 scanf("%d%d%d",&u,&v,&w); 33 add(u,v,w);add(v,u,w); 34 } 35 int l=0,r=10005; 36 while(l<r){ 37 memset(vis,0,sizeof(vis)); 38 int mid=(l+r)>>1; 39 check(s,mid); 40 if(vis[t]) r=mid; 41 else l=mid+1; 42 } 43 printf("%d",l); 44 return 0; 45 }
2.二分+BFS:
与DFS思路相同。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<queue> 5 using namespace std; 6 const int N=20005; 7 int n,m,s,t; 8 int head[N],tot,dis[N],vis[N]; 9 struct node{ 10 int to,next,w; 11 }edge[N<<1]; 12 void add(int u,int v,int w){ 13 edge[tot].to=v; 14 edge[tot].next=head[u]; 15 edge[tot].w=w; 16 head[u]=tot++; 17 } 18 void check(int u,int x){ 19 queue<int> q; 20 q.push(u); vis[u]=1; 21 while(!q.empty()){ 22 int u=q.front(); q.pop(); 23 for(int i=head[u];i!=-1;i=edge[i].next){ 24 int v=edge[i].to; 25 if(edge[i].w>x) continue; 26 if(vis[v]) continue; 27 vis[v]=1; 28 q.push(v); 29 } 30 } 31 } 32 int main(){ 33 memset(head,-1,sizeof(head)); 34 scanf("%d%d%d%d",&n,&m,&s,&t); 35 for(int i=1;i<=m;i++){ 36 int u,v,w; 37 scanf("%d%d%d",&u,&v,&w); 38 add(u,v,w);add(v,u,w); 39 } 40 int l=0,r=10005; 41 while(l<r){ 42 memset(vis,0,sizeof(vis)); 43 int mid=(l+r)>>1; 44 check(s,mid); 45 if(vis[t]) r=mid; 46 else l=mid+1; 47 } 48 printf("%d",l); 49 return 0; 50 }
3.二分+并查集:
用并查集维护s,t是否连通。如果边权小于等于mid,那么就将两个点合并。最后看看find(s),find(t)是否相同。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<queue> 5 using namespace std; 6 const int N=20005; 7 int n,m,s,t; 8 int head[N],tot,dis[N],vis[N],f[N]; 9 struct node{ 10 int to,next,w; 11 }edge[N<<1]; 12 struct Node{ 13 int u,v,w; 14 }q[N]; 15 void add(int u,int v,int w){ 16 edge[tot].to=v; 17 edge[tot].next=head[u]; 18 edge[tot].w=w; 19 head[u]=tot++; 20 } 21 int find(int x){ 22 if(f[x]!=x) f[x]=find(f[x]); 23 return f[x]; 24 } 25 void unionn(int u,int v){ 26 int r1=find(u),r2=find(v); 27 if(r1!=r2) f[r1]=r2; 28 } 29 bool check(int x){ 30 for(int i=1;i<=n;i++) f[i]=i; 31 for(int i=1;i<=m;i++){ 32 if(q[i].w<=x){ 33 unionn(q[i].u,q[i].v); 34 } 35 } 36 if(find(s)==find(t)) return 1; 37 return 0; 38 } 39 int main(){ 40 memset(head,-1,sizeof(head)); 41 scanf("%d%d%d%d",&n,&m,&s,&t); 42 for(int i=1;i<=m;i++){ 43 int u,v,w; 44 scanf("%d%d%d",&u,&v,&w); 45 q[i].u=u; q[i].v=v; q[i].w=w; 46 } 47 int l=0,r=10005; 48 while(l<r){ 49 memset(vis,0,sizeof(vis)); 50 int mid=(l+r)>>1; 51 if (check(mid)) r=mid; 52 else l=mid+1; 53 } 54 printf("%d",l); 55 return 0; 56 }