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

最近刷水太多标注一下防止它淹没在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 }*/ 

 

posted @ 2016-10-29 00:00  iiyiyi  阅读(383)  评论(0编辑  收藏  举报