【题目】http://acm.scu.edu.cn/soj/problem.action?id=4527
【题意】从1点走到n点,有m条边,每个边有最大的宝藏通行量和通过需要的时间。问在能否在炸弹爆炸前到达n点,若能,求此时最多能带多少宝藏?
【思路】二分能带的宝藏量,宝藏通行量小于带的宝藏量的路就不能走了,用迪杰斯特拉求最快到n点的时间,如果小于等于炸弹爆炸的时间,那么就存下这个值,再多带点宝藏试试;如果这个时间大于爆炸时间或者根本到不了n点(dis[n]=inf),那么就少带点宝藏试试。
【重点】二分的上下限:l=mid+1,r=mid-1,l<=r;;;最后会r=l-1;实在找不到正确的答案就枚举x,r,l,x四个值找最优。
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
const int M=50005;
const int N=10005;
const int inf=2e9+10;
int n,m,K;
struct node
{
int u,v,dis;
ll cap;
int nxt;
} edge[M*4];
int head[M],ei;
void addedge(int u,int v,ll cap,int dis)
{
edge[ei].u=u,edge[ei].v=v,edge[ei].cap=cap,edge[ei].dis=dis;
edge[ei].nxt=head[u];
head[u]=ei++;
edge[ei].u=v,edge[ei].v=u,edge[ei].cap=cap,edge[ei].dis=dis;
edge[ei].nxt=head[v];
head[v]=ei++;
}
void init()
{
memset(head,-1,sizeof(head));
ei=0;
}
int dist[N];
bool vis[N];
ll d[M];
struct HeapNode
{
ll d,u;
bool operator < (const HeapNode& rhs)const
{
return d>rhs.d;
}
};
priority_queue<HeapNode>Q;
bool done[M]= {0};
bool dj(ll Mx)//DJ
{
memset(done,0,sizeof(done));
while(!Q.empty())
Q.pop();
int s=1;
for(int i=1; i<=n; i++)
d[i]=inf;
d[s]=0;
Q.push(HeapNode{0,s});
while(!Q.empty())
{
HeapNode x=Q.top();
Q.pop();
int u=x.u;
if(done[u])
continue;
done[u]=1;
for(int i=head[u]; i!=-1; i=edge[i].nxt)
{
node &e=edge[i];
if(e.cap<Mx)
continue;
if(d[e.v]>d[u]+e.dis)
{
d[e.v]=d[u]+e.dis;
Q.push(HeapNode{d[e.v],e.v});
}
}
}
if(d[n]<=K)
return 1;
return 0;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
init();
ll mw=-1;
scanf("%d%d%d",&n,&m,&K);
for(int i=0; i<m; i++)
{
int u,v,dis;
ll cap;
scanf("%d%d%lld%d",&u,&v,&cap,&dis);
addedge(u,v,cap,dis);
mw=max(mw,cap);
}
ll l=0,r=mw;
ll mid,ans=-1;
while(l<=r)
{
mid=(l+r)/2;
if(dj(mid))
{
l=mid+1;
ans=mid;
}
else
r=mid-1;
}
if(ans==-1)
printf("Poor RunningPhoton!\n");
else
printf("%lld\n",ans);
}
}