HDU 3631 Shortest Path 最短路

         从这个题我想说一下分析题目数据的技巧和重要性。题目大意是:给定一个有向图,点数  N <= 300, 边数 M <= 10^6,然后有Q次询问(Q <= 10^6 ); 每次询问有两种操作:1) 标记一个点 v,如果这个点已经被标记过,输出“ERROR” ; 2) 求两个点u和v的最短路,要求最短路上的点必须全部被标记过;

         网络赛我就悲剧了,没有好好分析数据,竟然真的对于每次询问求了一遍最短路,到最后也是TLE,真是傻X到家了,唉。。。

         我们可以看到,点数很少,只有300,而题目中的询问次数高达10^6,这个对比应该使我们想到,我们需要一个算法能够以O(1)知道任意两个点的最短路,很明显,这10^6的询问里真正有用的标记次数只有300,剩下的除了标记已经标记的点全部是求最短路,除了O(1)任何一个复杂度我们都承受不了。所以算法就出来了,只有floyd能够满足。想到floyd就豁然开朗了,每次标记一个点用O(n^2)进行更新,最多更新n次,所以复杂度是O(n^3),加上询问,复杂度依然够,这个题于是就解决了。

          学到了一点,看到一个题一定要仔细分析,不要上来就做。就像这个,本来floyd复杂度是最短路里最高的,但他的好处是任意两个点查询O(1),所以如果仔细分析就会想到。其他的,管你是堆优化的dijkstra,还是SPFA,就挂着吧。。。

          #include <cstdio> #include <cstring> #define min(a,b) ((a)<(b)?(a):(b)) #define INF 0x1f1f1f1f using namespace std; int n; int dist[310][310]; bool flag[310]; inline void floyd(int k){ for(int i = 0;i < n; ++i) for(int j = 0;j < n; ++j) if(dist[i][j] > dist[i][k] + dist[k][j]) dist[i][j] = dist[i][k] + dist[k][j]; } int main() { int T = 0, Q, m, u, v, w; while(scanf("%d %d %d",&n, &m, &Q) != EOF){ if(n == 0 && m == 0 && Q == 0) break; T ++; if(T != 1) printf("/n"); printf("Case %d:/n",T); memset(dist,0x1f,sizeof(dist)); memset(flag,false,sizeof(bool)*(n+2)); for(int i = 0;i < n; ++i) dist[i][i] = 0; while(m--){ scanf("%d %d %d",&u, &v, &w); dist[u][v] = min(dist[u][v],w); } while(Q--){ scanf("%d",&w); if(w == 0){ scanf("%d",&u); if(flag[u])printf("ERROR! At point %d/n",u); else { flag[u] = true; floyd(u); } }else{ scanf("%d %d",&u, &v); if(!(flag[u] && flag[v])) printf("ERROR! At path %d to %d/n",u,v); else if(dist[u][v] == INF) printf("No such path/n"); else printf("%d/n",dist[u][v]); } } } } 

你可能感兴趣的:(算法,优化,网络,Path)