JDOJ 1070: phoneline
JDOJ 1070: phoneline
Description
小h最近准备给家里新装条电话线,好让他在奥运假期能够天天上网冲浪,不用再忍受那昂贵的无线上网。 电信局的工作人员对小h说,电话线网络上有n个站点,它们用m条边来连接,小h家的站点在1号,连接的终点在n号,站点之间有电线连接,而且有一定的费用,然后因为暑期的原因,在1号站点连接到n号站点的线路上有k条线是免费的,然后在这条线路剩下的线中费用最大的为小h连接到n号站要付的费用。 当然,小h希望他要付的钱最少,于是他就出了这道题,希望有人能帮帮他。
Input
第一行: n,m,k,意义如上文所述。(1<n<=1000,1<m<=n*(n-1)/2)
以下m行,每行3个正整数s,t,cost,指从s站到t站的费用是cost.(即t到s的费用也是cost)
1<s,t<=n,0<=cost<=10000
注意:可能会出现重边或自环
Output
一个正整数,表示最小的费用。
Sample Input
5 6 1 2 1 3629 3 2 8034 4 3 7348 5 4 3689 4 4 7266 5 5 6088
Sample Output
7348
题解:
和运输计划这道题的思路有些同源(其实差距还是蛮大的)
一看到最长路最短想二分答案。
判断当前答案是否合法的思路:把全图所有比当前答案大的边全部打上标记,统计从1到n最少能经过多少条带标记的边,如果大于k,就不合法,小于k,就合法了。
如何统计“最少经过多少条带标记的边呢”?很简单,新建一个边权数组跑最短路即可。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define R register
using namespace std;
const int maxn=1010;
const int maxm=5*1e5;
int n,m,k,maxx;
bool v[maxn];
int dist[maxn];
int tot,to[maxm<<1],nxt[maxm<<1],val[maxm<<1],head[maxn],val1[maxm<<1];
char *p1,*p2,buf[100000];
#define nc() (p1==p2 && (p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
inline int read()
{
int x=0,f=1;
char ch=nc();
while(ch<'0'||ch>'9')
{
if(ch=='-')
f=-1;
ch=nc();
}
while(ch>='0'&&ch<='9')
x=x*10+ch-'0',ch=nc();
return x*f;
}
inline void add(int x,int y,int z)
{
to[++tot]=y;
nxt[tot]=head[x];
val[tot]=z;
head[x]=tot;
}
inline void dijkstra(int start)//源点
{
int temp,k,y;
memset(dist,0x3f,sizeof(dist));
memset(v,0,sizeof(v));
dist[start]=0;
for(R int i=1;i<=n;i++)
{
temp=1<<30;
for(R int j=1;j<=n;j++)
if(dist[j]<temp && v[j]==0)
k=j,temp=dist[j];
v[k]=1;
for(R int j=head[k];j;j=nxt[j])
{
y=to[j];
if(dist[y]>dist[k]+val1[j])
dist[y]=dist[k]+val1[j];
}
}
}
inline void dfs(int d)
{
for(R int i=1;i<=n;i++)
for(R int j=head[i];j;j=nxt[j])
if(val[j]>d)
val1[j]=1;
}
inline bool check(int x)
{
memset(val1,0,sizeof(val1));
dfs(x);
dijkstra(1);
return dist[n]>k?0:1;
}
int main()
{
n=read();m=read();k=read();
for(R int i=1;i<=m;i++)
{
int x,y,z;
x=read();y=read();z=read();
add(x,y,z);
add(y,x,z);
maxx=max(maxx,z);
}
int l=0,r=maxx;
while(l<r)
{
int mid=(l+r)>>1;
if(check(mid))
r=mid;
else
l=mid+1;
}
printf("%d",l);
return 0;
}