您的位置:首页 > 其它

【Floyd(并非水题orz)】BZOJ4093-[Usaco2013 Dec]Vacation Planning

2016-10-29 00:00 316 查看
最近刷水太多标注一下防止它淹没在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 }*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: