【刷题】【最短路】架设电话线

在加权无向图上求出一条从1号结点到n号结点的路径,使路径上第k+1大的边权尽量小。

解读:二分搜索答案,求>mid的边的数量最好是k,否则就少一点点

#include<cstdio>
#include<cstdlib>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
int n,m,k;
const int N=1003;
struct node
{
    int v,w;
    node(int vv,int ww)
    { v=vv,w=ww; }
    node(){}
};
vector <node > g[N];
int sz[N];

struct nd
{
    int v,d,cnt;
    bool operator < (const nd & o) const
    { return d>o.d; }
    nd(int vv,int dd,int c)
    { v=vv,d=dd,cnt=c; }
    nd(){}
};
priority_queue <nd> q;
int dis[N][1003],mx;//就是求小于mid的边是不是 大于等于 k 
bool check(int mid)
{
    while(!q.empty() ) q.pop() ;
    memset(dis,-1,sizeof(dis));
    dis[1][0]=0,q.push(nd(1,0,0));
    
    int ans=k+1;
    while(!q.empty() )
    {
        nd t=q.top() ;q.pop() ;
        if(t.d !=dis[t.v ][t.cnt ]) continue;
        if(t.v ==n)
        {
            ans=t.cnt ;
            break;
        }
        
        for(int i=0;i<sz[t.v ];i++)
        {
            int nx=g[t.v ][i].v ,dd,stp=t.cnt ;
            if(g[t.v ][i].w > mid) dd=dis[t.v ][stp],stp++;
            else dd=max(g[t.v ][i].w ,dis[t.v ][stp]);
            
            if(stp>k) continue;
            if(dd < dis[nx][stp] || dis[nx][stp]==-1)
            {
                dis[nx][stp]=dd;
                q.push(nd(nx,dd,stp)); 
            }
        }
    }
    
    return ans<=k;
}

int main()
{
    scanf("%d%d%d",&n,&m,&k);
    int u,v,w;
    while(m--)
    {
        scanf("%d%d%d",&u,&v,&w);
        g[u].push_back(node(v,w));
        g[v].push_back(node(u,w));  
    }
    for(int i=1;i<=n;i++)
        sz[i]=g[i].size() ;
    
    int l=0,r=1<<30,ans;
    if(!check(r))
        printf("-1\n");
    else
    {    
        while(l<r)
        {
            int mid=(l+r)>>1;
            if(check(mid)) r=mid;
            else l=mid+1;
        }
        printf("%d\n",l);
    }
    
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/xwww666666/p/11669601.html