最近刷水太多标注一下防止它淹没在silver的水题中……我成为了本题,第一个T掉的人QAQ
【题目大意】
Bovinia设计了连接N (1 < = N < = 20,000)个农场的航班。对于任何航班,指定了其中的k个农场作为枢纽。 (1 < = K <= 200 , K < = N)。
目前,共有M种单向航班( 1 < = M < = 20,000 ),第i个航班从农场u_i至农场v_i花费d_i ( 1 < = d_i < =10,000 )美元。航班保证u_i或者v_i至少有一个是枢纽,任意两个农场至多只有一个航班,保证u_i≠v_i。
Bessie负责票务服务。共收到Q个度假请求,(1 < = Q < = 50,000),其中第i个请求是从农场a_i至农场b_i 。请帮助她计算,每个请求是否满足 ,并计算:能满足的度假请求的最小费用总和。
【思路】
首先我们会思考一个问题:为什么要给出中枢?显然这是一个不必要信息,即即使没有中枢本题也是可以求解的。那么只有一种可能性:优化。
显然,每个非中枢的周围必定是中枢,也就是说,中枢间可以通过直接相连,或通过一个非中枢点连接。预处理 直接相连 或 间隔一个非中枢点 相连的两个中枢的距离,然后跑Floyd得出所有中枢之间的最短路。这里写堆优化dijkstra会快一些,
然而我懒。
以下灰字是我脑补出来的T掉的做法。按照我的做法我们直接进入查询,如果ab都是中枢,用预处理的信息。否则就枚举旁边的中枢再加上边长。这样最糟糕的情况是两个都不是中枢,那么两边都要枚举。由于Q很大,这些时间复杂度都累在了Q里面,药丸。果然成为了该题第一个T掉的人。
接下来处理出所有的中枢到所有节点之间的最短路。由于已知两个中枢(u,v)之间的最短路,对于从v出发抵达的下一个农场vv,很容易得到(u,vv)。
最后对于查询的(a,b),如果a是一个中枢,直接可以利用上一步处理出来的信息。否则枚举a指向的每一个中枢c和b之间的最短路,再加上ac的距离,最小的那个即为最短路。
我觉得USACO上算的时间复杂度有点诡。
【错误点】
第二次的dis[i][j]表示第i个中枢到农场j的距离,前一个是中枢的编号,后一个是农场的编号。
写的时候老是弄晕掉。
结果这道题写了我将近三分之二场noip的时间。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int MAXK=200+5; 5 const int MAXN=20000+50; 6 const ll INF=1e12; 7 struct node 8 { 9 int to,dis; 10 }; 11 vector<node> E[MAXN]; 12 int n,m,k,q; 13 ll d[MAXK][MAXK],dis[MAXK][MAXN]; 14 int id[MAXN],num[MAXN]; 15 16 void addedge(int u,int v,int w) 17 { 18 E[u].push_back((node){v,w}); 19 } 20 21 void init() 22 { 23 scanf("%d%d%d%d",&n,&m,&k,&q); 24 memset(id,0,sizeof(id)); 25 26 for (int i=1;i<=m;i++) 27 { 28 int u,v,w; 29 scanf("%d%d%d",&u,&v,&w); 30 addedge(u,v,w); 31 } 32 for (int i=1;i<=k;i++) 33 { 34 int x; 35 scanf("%d",&x); 36 id[x]=i,num[i]=x; 37 } 38 } 39 40 void prep() 41 { 42 for (int i=1;i<=k;i++) 43 for (int j=1;j<=k;j++) 44 d[i][j]=INF; 45 for (int i=1;i<=k;i++) d[i][i]=0; 46 for (int i=1;i<=k;i++) 47 { 48 int u=num[i]; 49 for (int j=E[u].size()-1;j>=0;j--) 50 { 51 int v=E[u][j].to; 52 if (id[v]) d[i][id[v]]=min(d[i][id[v]],(ll)E[u][j].dis); 53 else 54 { 55 for (int _k=E[v].size()-1;_k>=0;_k--) 56 { 57 int vto=E[v][_k].to; 58 if (id[vto] && vto!=num[i]) d[id[u]][id[vto]]=min(d[id[u]][id[vto]],(ll)E[u][j].dis+(ll)E[v][_k].dis); 59 } 60 } 61 } 62 } 63 64 for (int _k=1;_k<=k;_k++) 65 for (int i=1;i<=k;i++) 66 for (int j=1;j<=k;j++) 67 if (i!=j && j!=_k && _k!=i) d[i][j]=min(d[i][j],d[i][_k]+d[_k][j]); 68 } 69 70 void prep2() 71 { 72 for (int i=1;i<=k;i++) 73 for (int j=1;j<=n;j++) dis[i][j]=INF; 74 for (int i=1;i<=k;i++) 75 for (int j=1;j<=k;j++) dis[i][num[j]]=d[i][j]; 76 77 78 79 for (int i=1;i<=k;i++) 80 { 81 for (int _k=0;_k<E[num[i]].size();_k++)//注意这里是E[num[i]]不是num[i],检查了40分钟才发现QAQ 82 for (int j=1;j<=k;j++) 83 { 84 int to=E[num[i]][_k].to; 85 dis[j][to]=min(dis[j][to],d[j][i]+E[num[i]][_k].dis); 86 } 87 } 88 } 89 90 void solve() 91 { 92 int t=0; 93 ll totalans=0; 94 for (int i=0;i<q;i++) 95 { 96 int a,b; 97 scanf("%d%d",&a,&b); 98 ll ans=INF; 99 if (id[a]) ans=dis[id[a]][b]; 100 else 101 { 102 for (int j=0;j<E[a].size();j++) 103 { 104 int v=E[a][j].to; 105 if (id[v]) ans=min(ans,E[a][j].dis+dis[id[v]][b]); 106 } 107 } 108 if (ans<INF) 109 { 110 totalans+=ans; 111 t++; 112 } 113 } 114 printf("%d\n",t); 115 printf("%d",totalans); 116 } 117 118 int main() 119 { 120 init(); 121 prep(); 122 prep2(); 123 solve(); 124 return 0; 125 } 126 127 /* 128 TLE的solve,答案是正确的QAQ 129 void solve() 130 { 131 int t=0; 132 ll totalans=0; 133 for (int i=1;i<=q;i++) 134 { 135 int a,b; 136 ll ans=INF; 137 scanf("%d%d",&a,&b); 138 if (id[a] && id[b]) ans=d[id[a]][id[b]]; 139 else if (id[a]) 140 { 141 for (int ib=0;ib<rE[b].size();ib++) ans=min(ans,d[id[a]][id[rE[b][ib].to]]+(ll)rE[b][ib].dis); 142 } 143 else if (id[b]) 144 { 145 for (int ia=0;ia<E[a].size();ia++) ans=min(ans,d[id[E[a][ia].to]][id[b]]+(ll)E[a][ia].dis); 146 } 147 else 148 { 149 for (int ia=0;ia<E[a].size();ia++) 150 for (int ib=0;ib<rE[b].size();ib++) 151 { 152 ll now=(ll)E[a][ia].dis+(ll)rE[b][ib].dis; 153 now+=d[id[E[a][ia].to]][id[rE[b][ib].to]]; 154 ans=min(ans,now); 155 } 156 } 157 if (ans!=INF) t++,totalans+=ans; 158 } 159 printf("%d\n",t); 160 printf("%lld",totalans); 161 }*/