Voluntary Hotel
题意:
有点乱。。。
有n(1e4)个点。 共有m(1e4)条无向边边。有边权,边权是两个点的距离(1e9),其中有p(100)个点是医院,第 i 个点在点 yi[i] 处,q个宾馆,第 i 个馆在点 y[i] 处,可以最多容纳 h[i] 个人,有 r 个医生,家在s[i]的点,要去第k[i]个医院上班,k[i] >=1 && k[i] <= p; k[i]是下标也就是在点yi[k[i]]处上班。医生可以住宾馆,然后医生去上班的最远距离是d,问d最小是多少。。。
好绕。。。
题解:
首先找最大的最小值这种基本都是二分的吧,就考虑怎么check,
如果家到他去医院的距离小于等于x的话就不用住酒店了。
剩下的人就是在宾馆住,去同一个医院的可以一视同仁,然后就是给这些医生安排酒店了,,怎么安排? 我想不到的,,
网络流 建立源点到宾馆的边,边权为宾馆的最多容纳人数,宾馆到医院的边,边权为inf,医院到汇点的边,边权为剩下的那些医生要去每个医院的人数,宾馆到医院的边中必须满足这个医院到这个宾馆的距离小于等于x。
然后跑一个最大流,如果可以最大流等于剩下的人数,那么就符合,否则不符合,
于是就可以先预处理一个每个医院为源点到其他地方的最短路。医院有100个,点有1e4个。所以不会超时
然后直接二分就可以。
代码就是比较头疼的了。。这么长的代码,害怕wa,找bug找死了。。
代码:
#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
typedef pair<int,ll> pii;
const int maxn = 1e4+5;
const ll inf = 0x3f3f3f3f3f3f3f3f;
struct Edge
{
int nex,id;
ll val;
}edge[maxn<<2];
int head[maxn];
int cnt;
void add(int x,int y,ll val)
{
edge[cnt].val = val;
edge[cnt].id = y;
edge[cnt].nex = head[x];
head[x] = cnt++ ;
}
int n,m,p,q,r;
int yi[maxn];
ll dis[105][10005];
int vis[maxn];
struct cmp
{
bool operator()(const pii & a, const pii & b){
return a.second > b.second;
}
};
priority_queue<pii,vector<pii>,cmp>qq;
void djs(int s,int k)
{
for (int i = 1; i <= n; i ++ )
{
dis[k][i] = inf;
vis[i] = 0;
}
dis[k][s] = 0;
qq.push(make_pair(s,0));
while(!qq.empty())
{
pii t = qq.top();
qq.pop();
int v= t.first;
if(vis[v])
continue;
vis[v] = 1;
for (int i = head[v]; ~i ; i = edge[i].nex)
{
int p = edge[i].id;
if(dis[k][p] > dis[k][v] + edge[i].val)
{
dis[k][p] = dis[k][v] + edge[i].val;
qq.push(make_pair(p,dis[k][p]));
}
}
}
}
const int M = 105;
int y[M]; //宾馆标号
int h[M]; //最多住的人
int s[1000006]; //每个医生的家
int k[1000006]; //每个医生要去的医院
int head2[M<<4];
Edge edge2[maxn<<2];
int cnt2;
void add2(int x,int y,int val)
{
edge2[cnt2].id = y;
edge2[cnt2].val = val;
edge2[cnt2].nex = head2[x];
head2[x] = cnt2 ++ ;
}
int st,et;
queue<int> qt;
int dep[M << 3];
bool bfs()
{
for (int i = 1; i <= et; i ++ )
dep[i] = 0;
qt.push(st);
dep[st] = 1;
while(!qt.empty())
{
int x = qt.front();
qt.pop();
// printf("%d\n",x);
for (int i = head2[x]; ~i; i = edge2[i].nex)
{
// printf("%d\n", i);;
int v = edge2[i].id;
if(dep[v] == 0 && edge2[i].val > 0)
{
qt.push(v);
dep[v] = dep[x] + 1;
}
}
}
return dep[et] != 0;
}
int dfs(int x,int flow)
{
// printf("%d\n",x);
if(x == et)
return flow;
int sum = 0;
for (int i = head2[x]; ~i; i = edge2[i].nex)
{
int v = edge2[i].id;
if(dep[v] == dep[x] + 1 && edge2[i].val > 0)
{
int s = dfs(v,min(edge2[i].val,1ll * flow));
edge2[i].val -= s;
edge2[i ^ 1].val += s;
sum += s;
flow -= s;
}
}
if(sum == 0)
dep[x] = 0;
return sum;
}
int sum[M];
bool pd(ll x)
{
memset(head2,-1,sizeof(head2));
memset(sum,0,sizeof(sum));
cnt2 = 0;
for (int i = 1; i <= r; i++ )
{
if(dis[k[i]][s[i]] <= x)
continue;
sum[k[i]] ++ ;
}
int sn = 0;
for (int i = 1; i <= p; i ++ )
{
sn += sum[i];
}
int ss = p + q;
st = ss + 1, et = ss + 2;
for (int i = 1; i <= p; i ++ )
{
add2(st,i,sum[i]);
add2(i,st,0);
}
for (int i = 1; i <= p; i ++ )
{
for (int j = 1; j <= q; j ++ )
{
if(dis[i][y[j]] <= x)
{
add2(i,j + p,10000007);
add2(j + p,i,0);
}
}
}
for (int i = 1; i <= q; i ++ )
{
add2(et,i + p,0);
add2(i + p,et,h[i]);
}
int ans =0 ;
while (1)
{
if(!bfs())
break;
ans += dfs(st,10000000);
}
// printf("%lld %d %d\n",x,ans,sn);
return ans == sn;
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d%d%d%d%d",&n,&m,&p,&q,&r);
cnt = 0;
for(int i= 1; i <= m; i ++ )
{
int x,y,val;
scanf("%d%d%d",&x,&y,&val);
add(x,y,val);
add(y,x,val);
}
for (int i = 1; i <= p; i ++ )
scanf("%d",&yi[i]);
for (int i = 1; i <= p; i ++ )
djs(yi[i],i);
// for (int i =1; i <= p; i ++ )
// {
// for (int j = 1; j <= n; j ++ )
// {
// printf("%lld ",dis[i][j]);
// }
// printf("\n");
// }
for (int i = 1; i <= q; i ++ )
scanf("%d%d",&y[i],&h[i]);
for (int i = 1; i <= r; i ++ )
scanf("%d%d",&s[i],&k[i]);
ll l = 0, rr = ll(1e14);
ll ans = ll(1e14);
while(l <= rr)
{
ll mid = l + rr >> 1;
if(pd(mid))
{
ans = mid;
rr = mid - 1;
}
else
l = mid + 1;
}
printf("%lld\n",ans);
}