小h最近准备给家里新装条电话线,好让他在奥运假期能够天天上网冲浪,不用再忍受那昂贵的无线上网。 电信局的工作人员对小h说,电话线网络上有n个站点,它们用m条边来连接,小h家的站点在1号,连接的终点在n号,站点之间有电线连接,而且有一定的费用,然后因为暑期的原因,在1号站点连接到n号站点的线路上有k条线是免费的,然后在这条线路剩下的线中费用最大的为小h连接到n号站要付的费用。 当然,小h希望他要付的钱最少,于是他就出了这道题,希望有人能帮帮他。
第一行: n,m,k,意义如上文所述。
以下m行,每行3个正整数s,t,cost,指从s站到t站的费用是cost.
(即t到s的费用也是cost)
注意:可能会出现重边或自环
n∈【1,1000】;m∈【1,n*(n-1)/2】
1< s,t <=n,0<=cost<=10000
一个正整数,表示最小的费用。
5 6 1
2 1 3629
3 2 8034
4 3 7348
5 4 3689
4 4 7266
5 5 6088
7348
最短路+二分
找到一条从1~n的路线,使其第k+1大值最小。这个k+1大值就是答案。而求最大值最小或者最小值最大就可以用二分来完成。但是这道题还有一点区别就是对于二分的边界没有一个明确的范围,所以不妨把所有边的最大值val_max当做这个边界。
首先要处理重边和自环,这个可以用一个hash数组,或者一个邻接矩阵来记录某一条边是否出现过,如果自环直接continue;重边则要保留最小的边权。
接着二分,假设现在一共有p条边,那么我们二分1~p得到左边的【1~mid】和右边的【mid+1~p】(//这里存的是一个结构体,每一个代表一个from,to,val,next)现在不妨令左边的边权为0,右边的边权为1。现在再运行一遍最短路,如果dis[n]<=k,则在左半边重复进行上述操作。反之则在右半边进行,直到只剩下一个点。这个点的val就是答案。
为什么这样做可以呢?二分的位置代表最大值,左边的值比这个值小,右边的值比这个值大。dis[n]表示从1~n中必须经过比二分出来的值大的边的个数,如果这个值小于k,则左移,反之右移。
Code:
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#define MAXN 1200
using namespace std;
typedef long long ll;
struct node
{
ll from;
ll to;
ll next;
ll val;
}edge[(MAXN*MAXN)>>1];
struct node2
{
ll from;
ll to;
ll next;
ll val;
}tmp[(MAXN*MAXN)>>1];
ll n,m,k,cnt,t,l,r,mid,ans,p;
ll map[MAXN][MAXN],head[MAXN],visit[MAXN],dis[MAXN];
ll min(ll a,ll b){return a<b?a:b;}
ll cmp(node2 a,node2 b){return a.val < b.val ? 1 : 0 ;}
void init()
{
memset(head,-1,sizeof(head));
cnt=1;
}
void addedge(ll from,ll to,ll val)
{
edge[cnt].from=from;
edge[cnt].to=to;
edge[cnt].val=val;
edge[cnt].next=head[from];
head[from]=cnt++;
}
void spfa(ll src)
{
memset(dis,0x3f,sizeof(dis));
memset(visit,0,sizeof(visit));
dis[src]=0;
visit[src]=1;
queue<int>q;
q.push(src);
while(q.size())
{
ll u=q.front();
q.pop();
for(ll i=head[u];i!=-1;i=edge[i].next)
{
ll v=edge[i].to;
if(dis[u]+edge[i].val<dis[v])
{
dis[v]=dis[u]+edge[i].val;
if(visit[v]==0)
{
visit[v]=1;
q.push(v);
}
}
}
visit[u]=0;
}
}
void pre_deal(ll mid)
{
init(); ///!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
for(ll i=1;i<=p;i++)
{
if(i<=mid)
{
addedge(tmp[i].from,tmp[i].to,0);
addedge(tmp[i].to,tmp[i].from,0);
}
else
{
addedge(tmp[i].from,tmp[i].to,1);
addedge(tmp[i].to,tmp[i].from,1);
}
}
}
ll check(ll mid)
{
pre_deal(mid);
spfa(1);
if(dis[n]<=k)
{
return 1;
}
return 0;
}
ll find(ll l,ll r)
{
ll ret=0;
while(l<r)
{
ll mid=(l+r)>>1;
if(check(mid))
{
r=mid;
}else
{
l=mid+1;
}
}
return r;
}
int main()
{
init();
scanf("%lld%lld%lld",&n,&m,&k);
t=m;
for(ll i=1;i<=m;i++)
{
ll a,b,c;
scanf("%lld %lld %lld",&a,&b,&c);
if(a==b)
t--;
if(map[a][b]>c&&a!=b)
{
map[a][b]=c;
continue;
}
if(!map[a][b]&&a!=b)
{
map[a][b]=c;
}
}
p=0;
for(ll i=1;i<=n;i++)
{
for(ll j=1;j<=n;j++)
{
if(map[i][j])
{
ll c=map[i][j];
tmp[++p].from=i;
tmp[p].to=j;
tmp[p].val=c;
}
}
}
sort(tmp+1,tmp+p+1,cmp);
printf("%lld\n",tmp[find(1,p)].val);
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/z_mendez/article/details/47278205