洛谷 P1396 营救(二分答案)

题目链接:https://www.luogu.com.cn/problem/P1396

注意要用双向边!!

1.二分+DFS:

二分路径最大值,然后DFS,如果边权小于mid,那么可以走,否则不可以走。DFS只需要判断s->t是否连通:跑一边DFS,然后用vis看能否连通。

 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 }
DFS

2.二分+BFS:

 与DFS思路相同。

 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 }
BFS

3.二分+并查集:

用并查集维护s,t是否连通。如果边权小于等于mid,那么就将两个点合并。最后看看find(s),find(t)是否相同。

 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 }
并查集
原文地址:https://www.cnblogs.com/New-ljx/p/13875319.html