最小生成树 || ( BFS && 二分答案) —— 营救

洛谷 1369 营救

题目描述

“咚咚咚……”“查水表!”原来是查水表来了,现在哪里找这么热心上门的查表员啊!小明感动的热泪盈眶,开起了门……

妈妈下班回家,街坊邻居说小明被一群陌生人强行押上了警车!妈妈丰富的经验告诉她小明被带到了t区,而自己在s区。

该市有m条大道连接n个区,一条大道将两个区相连接,每个大道有一个拥挤度。小明的妈妈虽然很着急,但是不愿意拥挤的人潮冲乱了她优雅的步伐。所以请你帮她规划一条从s至t的路线,使得经过道路的拥挤度最大值最小。

输入输出格式

输入格式:

第一行四个数字n,m,s,t。

接下来m行,每行三个数字,分别表示两个区和拥挤度。

(有可能两个区之间有多条大道相连。)

输出格式:

输出题目要求的拥挤度。

输入输出样例

输入样例#1:
   
   
3 3 1 3
1 2 2 2 3 1
1 3 3
输出样例#1:
2





说明

数据范围

30% n<=10

60% n<=100

100% n<=10000,m<=2n,拥挤度<=10000

题目保证1<=s,t<=n且s<>t,保证可以从s区出发到t区。

样例解释:

小明的妈妈要从1号点去3号点,最优路线为1->2->3。



Code 1 最小生成树解法

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define epx 10
using namespace std;

const int MAX_E = 20000 + epx;
const int MAX_V = 10000 + epx;

struct Edge
{
    int fm,to,dist;
} e[MAX_E];

int fa[MAX_V],n,m,s,t;

bool cmp(Edge a,Edge b)
{
    return a.dist < b.dist;
}

int getfa(int x)
{
    if (fa[x] == x)
        return fa[x];
    else return fa[x] = getfa(fa[x]);
}

int same(int x,int y)
{
    return getfa(x) == getfa(y);
}

void merge(int x,int y)
{
    int fax = getfa(x),fay = getfa(y);
    fa[fax] = fay;
}

int main()
{
    cin >> n >> m >> s >> t;
    for (int i=1;i<=m;i++)
    {
        cin >> e[i].fm >> e[i].to >> e[i].dist;
    }
    sort(e+1,e+m+1,cmp);
    for (int i=1;i<=n;i++)
    {
        fa[i] = i;
    }
    int rst = n,ans = -1;
    for (int i=1;i<=m && rst > 1;i++)
    {
        int x = e[i].fm,y = e[i].to;
        if (same(x,y)) continue;
        else
        {
            merge(x,y);
            rst--;
            ans = max(e[i].dist,ans);
            if (getfa(s) == getfa(t)) break; // 精髓 - 只要源点和终点被连接了,就可以退出了
        }
    }
    printf("%d",ans);
}




Code 2  BFS + 二分答案

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define MAXN 10005
using namespace std;
struct edge
{
    int vertex,weight;
    edge(int vv,int ww)
    {
        vertex = vv;
        weight = ww;
    }
};
vector<vector<edge> > edges(MAXN);
int vis[MAXN];
int xian[MAXN * 2];
int n,m,start,t;
bool bfs(int val)
{
    memset(vis,0,sizeof(vis));
    queue<int> q;
    q.push(start);
    vis[start] = true;
    while(!q.empty())
    {
        if (vis[t] == true) return true; // 在 val 的限制下,可以到达终点
        int temp = q.front();
        q.pop();
        for (int i=0;i<edges[temp].size();i++)
        {
            if (edges[temp][i].weight > val) continue;
            if (!vis[edges[temp][i].vertex])
            {
                q.push(edges[temp][i].vertex);
                vis[edges[temp][i].vertex] = true;
            }
        }
    }
    if (vis[t] == false)
        return false; // 在 val 的限制下,无法到达终点
}
int main()
{
    cin >> n >> m >> start >> t;
    start--;
    t--;
    for (int i=0;i<m;i++)
    {
        int fm,to,w;
        scanf("%d%d%d",&fm,&to,&w);
        fm--;to--;
        edges[fm].push_back(edge(to,w));
        edges[to].push_back(edge(fm,w));
        xian[i] = w;
    }
    sort(xian,xian+m);
    int l = 0,r = m - 1;
    int ans = 0x3f3f3f3f;
    while(l <= r)
    {
        int mid = (l + r)/2;
        if (bfs(xian[mid]))
        {
            r = mid - 1;
            ans = xian[mid];
        }
        else
        {
            l = mid + 1;
        }
    }
    cout << ans;
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值