2013校队选拔——最短路——二分最大边的最小值

1012: City Tour

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 63  Solved: 11
[Submit][Status][Web Board]

Description

Alice想要从城市A出发到城市B,由于Alice最近比较穷(不像集训队陈兴老师是个rich second),所以只能选择做火车从A到B。不过Alice很讨厌坐火车,火车上人比较多,比较拥挤,所以Alice有很严格的要求:火车的相邻两站间的最大距离尽可能的短,这样Alice就可以在停站的时候下车休息一下。当然Alice希望整个旅途比较短。

 

Input

有多组测试数据。
每组测试数据的第一行有两个整数N,M,A,B(N<=1000, M<=50000, N >=2, A,B<=N),其中N是城市的个数,M是城市间通火车的个数。
A,B是Alice起始的城市与目的地城市,城市的标号从1开始。
接下来的M行每行三个整数u,v,w表示从u到v和从v到u有一条铁路,距离为w, u,v<=N, w<=10000。

 

Output

对于每组测试数据输出满足Alice要求的从A到B的最短距离。

 

Sample Input

3 3 1 2
1 2 80
1 3 40
2 3 50
3 3 1 2
1 2 90
1 3 10
2 3 20
4 5 1 4
1 2 8
1 4 9
1 3 10
2 4 7
3 4 8

Sample Output

90
30
15
 
 
又是一年校队选拔,又坑在了二分这个题目上面。
这个题目最短路部分不难
关键是想到用二分
之前思路很混乱,我一度也在想要记录每条路的最大边权值,然后对求出来的最短路,优先选择最大边权值最小的那条。。。但是这种思路首先没有落实到二分这个方法上来,其次,我是想边求最短路的时候,边比较此时的最大边权,然后取小的。。非常混乱
记得上次显神就给我讲过最大值最小化问题,我竟然没有转化到这个最短路的题目来
题目条件要使得两个站之间的距离越短越好。。。因此是在站与站的距离越的情况下,来进行最短路。
因此,用二分枚举出最大边权值,(意思就是在该最大权值下,如果边权值大于它,则相当于不通),在枚举出的权值下,进行朴素的迪杰斯特拉最短路(安神用的SPFA,看起来很简洁。膜拜一下。)!
最后坑爹的二分调试了我几个小时(比赛之后)。发现二分真的不是那么好写。。尤其是这道题目,枚举出来的量稍有差池,就输不出正确的值来。
其实后来看了下浙西贫农的代码,忽然觉悟了,不是我的二分没写好,是在判断的时候,应该在边值可达的时候记录下此时的b点最短路值,否则总会发现输出inf
还得练习一下分治专题。
 
#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
#define inf 10000000
using namespace std;
int d[1005][1005];
int city[1005];
bool vis[1005];
int n,m,a,b;
int main()
{
    while (scanf("%d %d %d %d",&n,&m,&a,&b)!=EOF)
    {
        int i,j,k;
        int mmax=0;
        int mmin=inf;
        for (i=0; i<=n; i++)
        {
            for (j=1; j<=n; j++)
                d[i][j]=inf;
            city[i]=inf;
        }

        for (j=1; j<=m; j++)
        {
            int u,v,w;
            scanf("%d %d %d",&u,&v,&w);
            if (d[u][v]>w)
                d[u][v]=d[v][u]=w;
            if (mmax<w) mmax=w;
            if (mmin>w) mmin=w;
        }
        city[a]=0;
        int ans=0;
        int l=mmin,r=mmax,mid;
        while (l<r) //二分部分。
        {

            memset(vis,0,sizeof vis);
            mid=(l+r)/2;
            for (int i2=1;i2<=n;i2++)//每次二分都要重置最短路
            {
              city[i2]=inf;
            }
            city[a]=0;
            for (i=1;i<=n;i++)//进行朴素的Dijstla
            {
                int min=inf,loc;
                for (j=1;j<=n;j++)
                {
                    if (vis[j]) continue;
                    if (min>city[j])
                    {
                        min=city[j];
                        loc=j;
                    }
                }
                vis[loc]=1;
                for (k=1;k<=n;k++)
                {
                   if (d[loc][k]>mid) continue;
                   if(vis[k]) continue;
                   if (city[k]>city[loc]+d[loc][k])
                    city[k]=city[loc]+d[loc][k];

                }
            }
            if (city[b]>=inf) l=mid+1;
            else
{
ans=city[b];//应该在这里记录好结果。。。否则下一次二分如果是满足上面那个条件,则最终不是会输出inf r=mid;
} } printf(
"%d\n",ans); } return 0; }

 

posted @ 2013-08-22 16:53  KRisen  阅读(442)  评论(0编辑  收藏  举报