[USACO13DEC]假期计划(黄金)Vacation Planning (gold)
题目翻译不好,这里给出一份
题目背景
Awson是某国际学校信竞组的一只大佬。由于他太大佬了,于是干脆放弃了考前最后的集训,开车(他可是老司机)去度假。离开学校前,他打开地图,打算做些规划。
题目描述
他发现整个地图中有N(1<=N<=20000)个地点。对于所有的路线,指定了其中K(1<=K<=200,K<=N)个地点作为收费站。他设计了M(1<=M<=20000 )种单向的路线,第i条路线从地点Ui至Vi收费为Di(1<=Di<=10000)。路线保证Ui或Vi至少有一个是收费站,且Ui≠Vi,任意两个地点至多有一条路线。现在Awson准备进行规划。共提出Q(1<=Q<=50000)个询问,其中第i个询问是从地点Ai至地点Bi。请帮助他计算,每个请求是否满足(是否从地点Ai至地点Bi有可行路线),并计算:能满足的度假询问的最小费用总和。
输入输出格式
输入格式:
第1行:四个整数N,M,K,Q
第2~M+1行:三个整数Ui,Vi,Di
第M+2~M+K+1行:收费站的编号X (0<=X<=N)
第M+K+2~M+K+Q+1:两个整数,度假询问Ai,Bi
输出格式:
第1行:能够满足的度假询问数
第2行:能满足的度假询问的最小费用总和
输入输出样例
输入样例:
3 3 1 2
1 2 10
2 3 10
2 1 5
2
1 3
3 1
输出样例:
1
20
说明
样例解释:
第1个询问,路线设计为1->2->3,费用为20
第2个询问,无法满足
数据规模:
30%的数据有N<=100;
100%的数据有1<=N,M<=20000,1<=Q<=50000。
题解:
n很大,就算能O(1)求最短路也不行
但我们发现k很小,而且每条边至少有一个收费站
假设问u,v之间的最小距离,就是与u相邻的收费站与v的距离+边权
为包括u是收费站的情况,加入(u,u,0)边,修改部分会在代码中标记
题目转化为了求每个收费站到每个点的距离,用SPFA
复杂度为O(km+k*k)
询问部分可知一个点相邻的收费站最多为k,所以
询问复杂度为O(Q*k)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 struct Node 7 { 8 int next,dis,to; 9 }edge[200001]; 10 int head[100001],num,dist[201][20001],q[1000001],n,m,k,Q,p[10001],dis[301][301],b[100001],ans,cnt; 11 bool vis[100001]; 12 void add(int u,int v,int d) 13 { 14 num++; 15 edge[num].next=head[u]; 16 head[u]=num; 17 edge[num].to=v; 18 edge[num].dis=d; 19 } 20 void SPFA(int st,int j) 21 {int h,t,i;; 22 memset(dist[j],127,sizeof(dist[j])); 23 memset(vis,0,sizeof(vis)); 24 q[1]=st; 25 h=0;t=1; 26 dist[j][st]=0; 27 while (h<t) 28 { 29 h++; 30 h%=1000000; 31 int u=q[h]; 32 vis[u]=0; 33 for (i=head[u];i;i=edge[i].next) 34 { 35 int v=edge[i].to; 36 if (dist[j][v]>dist[j][u]+edge[i].dis) 37 { 38 dist[j][v]=dist[j][u]+edge[i].dis; 39 if (!vis[v]) 40 { 41 t++; 42 t%=1000000; 43 q[t]=v; 44 vis[v]=1; 45 } 46 } 47 } 48 } 49 for (i=1;i<=k;i++) 50 if (i!=j) 51 dis[j][i]=dist[j][p[i]]; 52 } 53 int main() 54 {int i,j,u,v,d; 55 cin>>n>>m>>k>>Q; 56 edge[0].next=-1; 57 for (i=1;i<=m;i++) 58 { 59 scanf("%d%d%d",&u,&v,&d); 60 add(u,v,d); 61 } 62 for (i=1;i<=k;i++) 63 { 64 scanf("%d",&p[i]); 65 b[p[i]]=i; 66 } 67 for (i=1;i<=k;i++) 68 { 69 SPFA(p[i],i); 70 } 71 while (Q--) 72 { 73 scanf("%d%d",&u,&v); 74 int s=1e9,x,y; 75 if (b[u]&&b[v]) 76 { 77 s=dis[b[u]][b[v]]; 78 } 79 else 80 for (i=head[u];i!=-1;i=edge[i].next) 81 { 82 if (b[u]) i=0; 83 if (i==0) x=u; 84 else x=edge[i].to; 85 if (b[x]) 86 { 87 if (s>edge[i].dis+dist[b[x]][v]) 88 s=edge[i].dis+dist[b[x]][v]; 89 } 90 } 91 //cout<<s<<endl; 92 if (s<1e9) 93 ans+=s,cnt++; 94 } 95 cout<<cnt<<endl<<ans; 96 }