• 【司雨寒】最短路专题总结


    最近在刷郏老大博客上的最短路专题

    【HDU】

    1548            A strange lift                    基础最短路(或bfs)

     1 //#define LOCAL
     2 #include <iostream>
     3 #include <cstdio>
     4 #include <cstring>
     5 using namespace std;
     6 
     7 const int maxn = 200 + 10;
     8 struct Point
     9 {
    10     int h;
    11     int times;
    12 }qu[maxn];
    13 int n, from, to, go[maxn], vis[maxn];
    14 int head, tail;
    15 int dir[2] = {1, -1};
    16 
    17 void BFS(void)
    18 {
    19     head = 0, tail = 1;
    20     qu[0].h = from, qu[0].times = 0;
    21     while(head < tail)
    22     {
    23         if(qu[head].h == to)
    24         {
    25             printf("%d
    ", qu[head].times);
    26             return;
    27         }
    28         for(int i = 0; i < 2; ++i)
    29         {
    30             int hh = qu[head].h + go[qu[head].h]*dir[i];
    31             if(hh>0 && hh<=n && (!vis[hh]))
    32             {
    33                 vis[hh] = 1;
    34                 qu[tail].h = hh;
    35                 qu[tail++].times = qu[head].times + 1;
    36             }
    37         }
    38         ++head;
    39     }
    40     printf("-1
    ");
    41 }
    42 
    43 int main(void)
    44 {
    45     #ifdef LOCAL
    46         freopen("1548in.txt", "r", stdin);
    47     #endif
    48 
    49     while(scanf("%d", &n) == 1 && n)
    50     {
    51         scanf("%d%d", &from, &to);
    52         for(int i = 1; i <= n; ++i)
    53             scanf("%d", &go[i]);
    54         memset(vis, 0, sizeof(vis));
    55         BFS();
    56     }
    57     return 0;
    58 }
    代码君

    2544            最短路                           基础最短路

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <vector>
     4 #include <queue>
     5 #include <algorithm>
     6 #include <map>
     7 #define MP make_pair
     8 using namespace std;
     9 
    10 typedef pair<int, int> PII;
    11 
    12 const int maxn = 100 + 10;
    13 const int INF = 1000000000;
    14 
    15 struct Edge
    16 {
    17     int from, to, dist;
    18     Edge(int u, int v, int d):from(u), to(v), dist(d) {}
    19 };
    20 
    21 int n, m;
    22 int d[maxn];
    23 vector<Edge> edges;
    24 vector<int> G[maxn];
    25 bool done[maxn];
    26 
    27 void init()
    28 {
    29     for(int i = 1; i <= n; i++) G[i].clear();
    30     edges.clear();
    31 }
    32 
    33 void AddEdge(int from, int to, int dist)
    34 {
    35     edges.push_back(Edge(from, to, dist));
    36     int sz = edges.size();
    37     G[from].push_back(sz - 1);
    38 }
    39 
    40 void dijkstra()
    41 {
    42     memset(done, false, sizeof(done));
    43     d[0] = 0;
    44     for(int i = 2; i <= n; i++) d[i] = INF;
    45     priority_queue<PII, vector<PII>, greater<PII> > Q;
    46     Q.push(MP(0, 1));
    47     while(!Q.empty())
    48     {
    49         PII x = Q.top(); Q.pop();
    50         int u = x.second;
    51         if(done[u]) continue;
    52         done[u] = true;
    53         for(int i = 0; i < G[u].size(); i++)
    54         {
    55             Edge& e = edges[G[u][i]];
    56             if(d[e.to] > d[u] + e.dist)
    57             {
    58                 d[e.to] = d[u] + e.dist;
    59                 Q.push(MP(d[e.to], e.to));
    60             }
    61         }
    62     }
    63 }
    64 
    65 int main()
    66 {
    67     while(scanf("%d%d", &n, &m) == 2)
    68     {
    69         if(n == 0 && m == 0) break;
    70 
    71         init();
    72         int u, v, d;
    73         while( m-- ) { scanf("%d%d%d", &u, &v, &d); AddEdge(u, v, d); AddEdge(v, u, d); }
    74         dijkstra();
    75         printf("%d
    ", ::d[n]);
    76     }
    77 
    78     return 0;
    79 }
    Dijkstra

    3790             最短路径问题        最短路径上的最小花费

    在进行松弛操作的时候顺便记录下最小花费即可

    另外:注意重边

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 using namespace std;
     5 
     6 const int maxn = 1000 + 10;
     7 const int INF = 1000000000;
     8 int n, m, s, t;
     9 int G[maxn][maxn], P[maxn][maxn];
    10 int d[maxn], p[maxn];
    11 bool done[maxn];
    12 
    13 void init()
    14 {
    15     for(int i = 1; i <= n; i++)
    16         for(int j = 1; j <= n; j++)
    17             G[i][j] = P[i][j] = INF;
    18 }
    19 
    20 void dijkstra()
    21 {
    22     for(int i = 1; i <= n; i++) d[i] = p[i] = INF;
    23     d[s] = p[s] = 0;
    24     memset(done, false, sizeof(done));
    25     for(int i = 1; i <= n; i++)
    26     {
    27         int m = INF, x;
    28         for(int y = 1; y <= n; y++) if(!done[y] && d[y] <= m) m = d[x = y];
    29         done[x] = true;
    30         for(int y = 1; y <= n; y++)
    31         {
    32             if(d[y] > d[x] + G[x][y])
    33             {
    34                 d[y] = d[x] + G[x][y];
    35                 p[y] = p[x] + P[x][y];
    36             }
    37             else if(d[y] == d[x] + G[x][y] && p[y] > p[x] + P[x][y])
    38                 p[y] = p[x] + P[x][y];
    39         }
    40     }
    41 }
    42 
    43 int main()
    44 {
    45     while(scanf("%d%d", &n, &m) == 2)
    46     {
    47         if(!n && !m) break;
    48 
    49         init();
    50         int u, v, dist, price;
    51         while( m-- )
    52         {
    53             scanf("%d%d%d%d", &u, &v, &dist, &price);
    54             if(G[u][v] > dist)
    55             {
    56                 G[u][v] = G[v][u] = dist;
    57                 P[u][v] = P[v][u] = price;
    58             }
    59             else if(G[u][v] == dist && P[u][v] > price)
    60                 P[u][v] = P[v][u] = price;
    61         }
    62         scanf("%d%d", &s, &t);
    63 
    64         dijkstra();
    65         printf("%d %d
    ", d[t], p[t]);
    66     }
    67 
    68     return 0;
    69 }
    Dijkstra

    2066              一个人的旅行                       多源多汇,其实和普通最短路并没有什么变化

    同样要注意重边,除非后面的题明确说明没有重边,否则都要考虑这个问题

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 using namespace std;
     5 
     6 const int maxn = 1000 + 10;
     7 const int INF = 1000000000;
     8 
     9 int n, m, S, T, s[maxn], t[maxn];
    10 int G[maxn][maxn];
    11 int d[maxn];
    12 bool done[maxn];
    13 
    14 void init()
    15 {
    16     memset(G, 0x3f, sizeof(G));
    17 }
    18 
    19 void dijkstra()
    20 {
    21     memset(done, false, sizeof(done));
    22     for(int i = 1; i <= n; i++) d[i] = INF;
    23     for(int i = 0; i < S; i++) d[s[i]] = 0;
    24     for(int i = 1; i <= n; i++)
    25     {
    26         int m = INF, x;
    27         for(int y = 1; y <= n; y++) if(!done[y] && d[y] <= m) m = d[x = y];
    28         done[x] = true;
    29         for(int y = 1; y <= n; y++)
    30             if(d[y] > d[x] + G[x][y]) d[y] = d[x] + G[x][y];
    31     }
    32 }
    33 
    34 int main()
    35 {
    36     while(scanf("%d%d%d", &m, &S, &T) == 3)
    37     {
    38         init();
    39         n = 1;
    40         while( m-- )
    41         {
    42             int u, v, dist;
    43             scanf("%d%d%d", &u, &v, &dist);
    44             if(G[u][v] > dist) G[u][v] = G[v][u] = dist;
    45             n = max(n, max(u, v));
    46         }
    47         for(int i = 0; i < S; i++) { scanf("%d", s + i); n = max(n, s[i]); }
    48         for(int i = 0; i < T; i++) { scanf("%d", t + i); n = max(n, t[i]); }
    49 
    50         dijkstra();
    51         int ans = INF;
    52         for(int i = 0; i < T; i++) ans = min(ans, d[t[i]]);
    53         printf("%d
    ", ans);
    54     }
    55 
    56     return 0;
    57 }
    Dijkstra

    2112            HDU Today                       基础最短路

    可以用个map对地名进行编号

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <string>
     5 #include <map>
     6 using namespace std;
     7 
     8 int n, tot, s, t;
     9 const int maxn = 150 + 10;
    10 const int INF = 1000000000;
    11 int G[maxn][maxn];
    12 int d[maxn];
    13 bool done[maxn];
    14 
    15 map<string, int> id;
    16 
    17 void init()
    18 {
    19     memset(G, 0x3f, sizeof(G));
    20     id.clear();
    21     tot = 1;
    22 }
    23 
    24 int ID(string s)
    25 {
    26     if(!id.count(s)) id[s] = tot++;
    27     return id[s];
    28 }
    29 
    30 void dijkstra()
    31 {
    32     memset(done, false, sizeof(done));
    33     for(int i = 1; i < tot; i++) d[i] = INF;
    34     d[s] = 0;
    35     for(int i = 1; i < tot; i++)
    36     {
    37         int m = INF, x;
    38         for(int y = 1; y < tot; y++) if(!done[y] && d[y] <= m) m = d[x = y];
    39         done[x] = true;
    40         for(int y = 1; y < tot; y++) d[y] = min(d[y], d[x] + G[x][y]);
    41     }
    42 }
    43 
    44 int main()
    45 {
    46     while(scanf("%d", &n) == 1 && n + 1)
    47     {
    48         init();
    49         string st, ed;
    50         cin >> st >> ed;
    51         s = ID(st), t = ID(ed);
    52         while( n-- )
    53         {
    54             cin >> st >> ed;
    55             int dist; scanf("%d", &dist);
    56             int u = ID(st);
    57             int v = ID(ed);
    58             if(G[u][v] > dist) G[u][v] = G[v][u] = dist;
    59         }
    60 
    61         dijkstra();
    62         printf("%d
    ", d[t] == INF ? -1 : d[t]);
    63     }
    64 
    65     return 0;
    66 }
    Dijkstra

    1874            畅通工程续                     基础最短路

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 using namespace std;
     5 
     6 const int maxn = 200 + 10;
     7 const int INF = 0x3f3f3f3f;
     8 int n, m, s, t;
     9 
    10 int G[maxn][maxn];
    11 int d[maxn];
    12 bool done[maxn];
    13 
    14 void dijkstra()
    15 {
    16     memset(d, 0x3f, sizeof(d));
    17     d[s] = 0;
    18     memset(done, false, sizeof(done));
    19     for(int i = 0; i < n; i++)
    20     {
    21         int m = INF, x;
    22         for(int y = 0; y < n; y++) if(!done[y] && d[y] <= m) m = d[x = y];
    23         done[x] = true;
    24         for(int y = 0; y < n; y++) d[y] = min(d[y], d[x] + G[x][y]);
    25     }
    26 }
    27 
    28 int main()
    29 {
    30     while(scanf("%d%d", &n, &m) == 2)
    31     {
    32         memset(G, 0x3f, sizeof(G));
    33         while( m-- )
    34         {
    35             int u, v, dist;
    36             scanf("%d%d%d", &u, &v, &dist);
    37             if(G[u][v] > dist) G[u][v] = G[v][u] = dist;
    38         }
    39         scanf("%d%d", &s, &t);
    40         dijkstra();
    41         printf("%d
    ", d[t] == INF ? -1 : d[t]);
    42     }
    43 
    44     return 0;
    45 }
    Dijkstra

    1217            Arbitrage                      货币交换 Floyd求最大的兑换比率

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <string>
     5 #include <algorithm>
     6 #include <map>
     7 using namespace std;
     8 
     9 const int maxn = 30 + 10;
    10 int n, m;
    11 double d[maxn][maxn];
    12 map<string, int> id;
    13 
    14 void init()
    15 {
    16     id.clear();
    17     memset(d, 0, sizeof(d));
    18     for(int i = 0; i < n; i++) d[i][i] = 1;
    19 }
    20 
    21 void floyd()
    22 {
    23     for(int i = 0; i < n; i++)
    24         for(int j = 0; j < n; j++)
    25             for(int k = 0; k < n; k++)
    26                 d[i][j] = max(d[i][j], d[i][k] * d[k][j]);
    27 }
    28 
    29 int main()
    30 {
    31     int kase = 0;
    32     while(scanf("%d", &n) == 1 && n)
    33     {
    34         init();
    35         string s1, s2;
    36         for(int i = 0; i < n; i++) { cin >> s1; id[s1] = i; }
    37         scanf("%d", &m);
    38         double x;
    39         while( m-- )
    40         {
    41             cin >> s1;
    42             scanf("%lf", &x);
    43             cin >> s2;
    44             int u = id[s1], v = id[s2];
    45             d[u][v] = x;
    46         }
    47 
    48         floyd();
    49         bool ok = false;
    50         for(int i = 0; i < n; i++) if(d[i][i] > 1.0) { ok = true; break; }
    51         printf("Case %d: %s
    ", ++kase, ok ? "Yes" : "No");
    52     }
    53 
    54     return 0;
    55 }
    Floyd

    1245            Saving James Bond          计算几何  最短路

    这题用BFS过的,=_=

     1 #include <cstdio>
     2 #include <algorithm>
     3 #include <cmath>
     4 #include <queue>
     5 using namespace std;
     6 
     7 const int maxn = 100 + 10;
     8 const double INF = 1e8;
     9 const double eps = 1e-8;
    10 
    11 inline int dcmp(double x)
    12 {
    13     if(fabs(x) < eps) return 0;
    14     return x < 0 ? -1 : 1;
    15 }
    16 
    17 struct Point
    18 {
    19     double x, y;
    20     Point(double x = 0, double y = 0):x(x), y(y) {}
    21 }p[maxn];
    22 const Point O(0, 0);
    23 
    24 Point operator - (const Point& A, const Point& B)
    25 { return Point(A.x - B.x, A.y - B.y); }
    26 
    27 double Dot(const Point& A, const Point& B)
    28 { return A.x * B.x + A.y * B.y; }
    29 
    30 double Length(const Point& A) { return sqrt(Dot(A, A)); }
    31 
    32 double Dist(const Point& A, const Point& B) { return Length(A - B); }
    33 
    34 int n;
    35 double d;
    36 double dis[maxn][maxn];
    37 
    38 void build_graph()
    39 {
    40     for(int i = 1; i <= n; i++)
    41     {
    42         dis[i][i] = 0;
    43         for(int j = 1; j < i; j++)
    44             dis[i][j] = dis[j][i] = Dist(p[i], p[j]);
    45     }
    46     for(int i = 1; i <= n; i++)
    47     {
    48         dis[0][i] = fabs(Dist(p[i], O) - 7.5);
    49         dis[i][n + 1] = min(fabs(50.0 - fabs(p[i].x)), fabs(50.0 - fabs(p[i].y)));
    50         dis[n + 1][i] = INF;
    51     }
    52     dis[0][n + 1] = INF;
    53 }
    54 
    55 double c[maxn];
    56 int step[maxn];
    57 
    58 void BFS()
    59 {
    60     for(int i = 1; i <= n + 1; i++) c[i] = INF;
    61     c[0] = 0;
    62     step[0] = 0;
    63     queue<int> Q;
    64     Q.push(0);
    65     while(!Q.empty())
    66     {
    67         int cur = Q.front(); Q.pop();
    68         for(int nxt = 1; nxt <= n + 1; nxt++)
    69         {
    70             if(dcmp(dis[cur][nxt] - d) <= 0)
    71             {
    72                 int t = dcmp(c[nxt] - dis[cur][nxt] - c[cur]);
    73                 if(t > 0 || (t == 0 && step[nxt] > step[cur] + 1))
    74                 {
    75                     c[nxt] = c[cur] + dis[cur][nxt];
    76                     step[nxt] = step[cur] + 1;
    77                     Q.push(nxt);
    78                 }
    79             }
    80         }
    81     }
    82 }
    83 
    84 int main()
    85 {
    86     while(scanf("%d%lf", &n, &d) == 2)
    87     {
    88         if(dcmp(d - 42.50) >= 0) { puts("42.50 %d"); continue; }
    89 
    90         for(int i = 1; i <= n; i++) scanf("%lf%lf", &p[i].x, &p[i].y);
    91         build_graph();
    92         BFS();
    93         if(dcmp(c[n + 1] - INF) == 0) puts("can't be saved");
    94         else printf("%.2f %d
    ", c[n + 1], step[n + 1]);
    95     }
    96 
    97     return 0;
    98 }
    BFS

    1317            XYZZY                     SPFA 判环

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <queue>
     4 #include <vector>
     5 using namespace std;
     6 
     7 const int maxn = 100 + 10;
     8 const int INF = 1000000000;
     9 
    10 int n;
    11 vector<int> G[maxn];
    12 int d[maxn], cnt[maxn], w[maxn];
    13 bool inq[maxn];
    14 
    15 bool SPFA()
    16 {
    17     memset(cnt, 0, sizeof(cnt));
    18     memset(inq, false, sizeof(inq));
    19     memset(d, 0, sizeof(d));
    20     queue<int> Q;
    21     Q.push(1);
    22     inq[1] = true;
    23     d[1] = 100;
    24 
    25     while(!Q.empty())
    26     {
    27         int u = Q.front(); Q.pop();
    28         inq[u] = false;
    29         cnt[u]++;
    30         if(cnt[u] > n + 1) continue;
    31         if(cnt[u] == n + 1) d[u] = INF; //有正环
    32         for(int i = 0; i < G[u].size(); i++)
    33         {
    34             int v = G[u][i];
    35             if(d[v] < d[u] + w[v])
    36             {
    37                 if(v == n) return true;
    38                 d[v] = d[u] + w[v];
    39                 if(!inq[v]) { inq[v] = true; Q.push(v); }
    40             }
    41         }
    42     }
    43     return false;
    44 }
    45 
    46 int main()
    47 {
    48     while(scanf("%d", &n) == 1 && n + 1)
    49     {
    50         for(int i = 1; i <= n; i++) G[i].clear();
    51 
    52         for(int i = 1; i <= n; i++)
    53         {
    54             int c;
    55             scanf("%d%d", w + i, &c);
    56             while(c--)
    57             {
    58                 int u; scanf("%d", &u);
    59                 G[i].push_back(u);
    60             }
    61         }
    62 
    63         printf("%s
    ", SPFA() ? "winnable" : "hopeless");
    64     }
    65 
    66     return 0;
    67 }
    SPFA

    1535            Invitation Cards            有向图的来回最短路,反向建图

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <vector>
     4 #include <queue>
     5 #include <map>
     6 #define MP make_pair
     7 using namespace std;
     8 
     9 typedef pair<int, int> PII;
    10 
    11 const int maxn = 1000000 + 10;
    12 
    13 struct Edge
    14 {
    15     int from, to, dist;
    16     Edge(int u, int v, int d):from(u), to(v), dist(d) {}
    17 };
    18 
    19 int n, m;
    20 
    21 vector<Edge> edges;
    22 vector<int> G[maxn];
    23 int d[maxn], u[maxn], v[maxn], w[maxn];
    24 bool done[maxn];
    25 
    26 void init()
    27 {
    28     for(int i = 1; i <= n; i++) G[i].clear();
    29     edges.clear();
    30 }
    31 
    32 void AddEdge(int from, int to, int dist)
    33 {
    34     edges.push_back(Edge(from, to, dist));
    35     int sz = edges.size();
    36     G[from].push_back(sz - 1);
    37 }
    38 
    39 void dijkstra()
    40 {
    41     memset(done, false, sizeof(done));
    42     memset(d, 0x3f, sizeof(d));
    43     d[1] = 0;
    44     priority_queue<PII, vector<PII>, greater<PII> > Q;
    45     Q.push(MP(0, 1));
    46 
    47     while(!Q.empty())
    48     {
    49         PII x = Q.top(); Q.pop();
    50         int u = x.second;
    51         if(done[u]) continue;
    52         done[u] = true;
    53         for(int i = 0; i < G[u].size(); i++)
    54         {
    55             Edge& e = edges[G[u][i]];
    56             if(d[e.to] > d[u] + e.dist)
    57             {
    58                 d[e.to] = d[u] + e.dist;
    59                 Q.push(MP(d[e.to], e.to));
    60             }
    61         }
    62     }
    63 }
    64 
    65 int main()
    66 {
    67     int T; scanf("%d", &T);
    68     while( T-- )
    69     {
    70         scanf("%d%d", &n, &m);
    71         for(int i = 0; i < m; i++) scanf("%d%d%d", u + i, v + i, w + i);
    72 
    73         int ans = 0;
    74 
    75         init();
    76         for(int i = 0; i < m; i++) AddEdge(u[i], v[i], w[i]);
    77         dijkstra();
    78         for(int i = 2; i <= n; i++) ans += d[i];
    79 
    80         init();
    81         for(int i = 0; i < m; i++) AddEdge(v[i], u[i], w[i]);
    82         dijkstra();
    83         for(int i = 2; i <= n; i++) ans += d[i];
    84 
    85         printf("%d
    ", ans);
    86     }
    87 
    88     return 0;
    89 }
    Dijkstra
     1 #include <cstdio>
     2 #include <cstring>
     3 #include <vector>
     4 #include <queue>
     5 using namespace std;
     6 
     7 const int maxn = 1000000 + 10;
     8 
     9 int n, m;
    10 int u[maxn], v[maxn], w[maxn];
    11 
    12 struct Edge
    13 {
    14     int from, to, dist;
    15     Edge(int u, int v, int d):from(u), to(v), dist(d) {}
    16 };
    17 
    18 vector<Edge> edges;
    19 vector<int> G[maxn];
    20 
    21 void init()
    22 {
    23     for(int i = 1; i <= n; i++) G[i].clear();
    24     edges.clear();
    25 }
    26 
    27 void AddEdge(int from, int to, int dist)
    28 {
    29     edges.push_back(Edge(from, to, dist));
    30     int sz = edges.size();
    31     G[from].push_back(sz - 1);
    32 }
    33 
    34 bool inq[maxn];
    35 int d[maxn];
    36 
    37 void SPFA()
    38 {
    39     queue<int> Q;
    40     memset(inq, false, sizeof(inq));
    41     memset(d, 0x3f, sizeof(d));
    42     inq[1] = true;
    43     Q.push(1);
    44     d[1] = 0;
    45 
    46     while(!Q.empty())
    47     {
    48         int u = Q.front(); Q.pop();
    49         inq[u] = false;
    50         for(int i = 0; i < G[u].size(); i++)
    51         {
    52             Edge& e = edges[G[u][i]];
    53             if(d[e.to] > d[u] + e.dist)
    54             {
    55                 d[e.to] = d[u] + e.dist;
    56                 if(!inq[e.to]) { inq[e.to] = true; Q.push(e.to); }
    57             }
    58         }
    59     }
    60 }
    61 
    62 int main()
    63 {
    64     int T; scanf("%d", &T);
    65     while(T--)
    66     {
    67         scanf("%d%d", &n, &m);
    68         for(int i = 0; i < m; i++) scanf("%d%d%d", u + i, v + i, w + i);
    69 
    70         int ans = 0;
    71 
    72         init();
    73         for(int i = 0; i < m; i++) AddEdge(u[i], v[i], w[i]);
    74         SPFA();
    75         for(int i = 2; i <= n; i++) ans += d[i];
    76 
    77         init();
    78         for(int i = 0; i < m; i++) AddEdge(v[i], u[i], w[i]);
    79         SPFA();
    80         for(int i = 2; i <= n; i++) ans += d[i];
    81 
    82         printf("%d
    ", ans);
    83     }
    84 
    85     return 0;
    86 }
    SPFA

    1546            Idiomatic Phrases Game       成语接龙,最短路

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <queue>
     4 #include <algorithm>
     5 using namespace std;
     6 
     7 const int maxn = 1000 + 10;
     8 const int INF = 0x3f3f3f3f;
     9 const int maxl = 200;
    10 
    11 int n;
    12 
    13 char dic[maxn][maxl];
    14 int w[maxn];
    15 int dis[maxn][maxn];
    16 int d[maxn];
    17 bool done[maxn];
    18 
    19 inline bool connect(int a, int b)
    20 {
    21     int l = strlen(dic[a]);
    22     for(int i = 0; i < 4; i++) if(dic[a][l-4+i] != dic[b][i]) return false;
    23     return true;
    24 }
    25 
    26 void dijkstra()
    27 {
    28     memset(d, 0x3f, sizeof(d));
    29     d[0] = 0;
    30     memset(done, false, sizeof(done));
    31     for(int i = 0; i < n; i++)
    32     {
    33         int x, m = INF;
    34         for(int y = 0; y < n; y++) if(d[y] <= m && !done[y]) m = d[x = y];
    35         done[x] = true;
    36         for(int y = 0; y < n; y++) d[y] = min(d[y], d[x] + dis[x][y]);
    37     }
    38 }
    39 
    40 int main()
    41 {
    42     //freopen("in.txt", "r", stdin);
    43 
    44     while(scanf("%d", &n) == 1 && n)
    45     {
    46         for(int i = 0; i < n; i++) scanf("%d %s", w + i, dic[i]);
    47 
    48         if(n == 1) { puts("-1"); continue; }
    49 
    50         //build_graph
    51         for(int i = 0; i < n; i++)
    52         {
    53             for(int j = 0; j < n; j++)
    54             {
    55                 if(i == j) { dis[i][j] = INF; continue; }
    56                 if(connect(i, j)) dis[i][j] = w[i];
    57                 else dis[i][j] = INF;
    58             }
    59         }
    60 
    61         dijkstra();
    62         printf("%d
    ", d[n - 1] == INF ? -1 : d[n - 1]);
    63     }
    64 
    65     return 0;
    66 }
    Dijkstra
     1 #include <cstdio>
     2 #include <cstring>
     3 #include <queue>
     4 using namespace std;
     5 
     6 const int maxn = 1000 + 10;
     7 const int maxl = 200;
     8 const int INF = 0x3f3f3f3f;
     9 
    10 int n;
    11 int d[maxn], w[maxn];
    12 vector<int> G[maxn];
    13 bool inq[maxn];
    14 char dic[maxn][maxl];
    15 
    16 inline bool connect(int a, int b)
    17 {
    18     int l = strlen(dic[a]);
    19     for(int i = 0; i < 4; i++) if(dic[a][l-4+i] != dic[b][i]) return false;
    20     return true;
    21 }
    22 
    23 void SPFA()
    24 {
    25     memset(inq, false, sizeof(inq));
    26     memset(d, 0x3f, sizeof(d));
    27     queue<int> Q;
    28     Q.push(0);
    29     inq[0] = true;
    30     d[0] = 0;
    31 
    32     while(!Q.empty())
    33     {
    34         int u = Q.front(); Q.pop();
    35         inq[u] = false;
    36         for(int i = 0; i < G[u].size(); i++)
    37         {
    38             int v = G[u][i];
    39             if(d[v] > d[u] + w[u])
    40             {
    41                 d[v] = d[u] + w[u];
    42                 if(!inq[v]) { inq[v] = true; Q.push(v); }
    43             }
    44         }
    45     }
    46 }
    47 
    48 int main()
    49 {
    50     //freopen("in.txt", "r", stdin);
    51 
    52     while(scanf("%d", &n) == 1 && n)
    53     {
    54         for(int i = 0; i < n; i++) scanf("%d %s", w + i, dic[i]);
    55 
    56         if(n == 1) { puts("-1"); continue; }
    57 
    58         //build_graph
    59         for(int i = 0; i < n; i++) G[i].clear();
    60         for(int i = 0; i < n; i++)
    61         {
    62             for(int j = 0; j < n; j++)
    63             {
    64                 if(i == j) continue;
    65                 if(connect(i, j)) G[i].push_back(j);
    66             }
    67         }
    68 
    69         SPFA();
    70         printf("%d
    ", d[n - 1] == INF ? -1 : d[n - 1]);
    71     }
    72 
    73     return 0;
    74 }
    SPFA

    2680            Choose the best route          最短路,多个源点

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <vector>
     4 #include <queue>
     5 #include <map>
     6 #define MP make_pair
     7 using namespace std;
     8 typedef pair<int, int> PII;
     9 
    10 const int maxn = 1000 + 10;
    11 const int INF = 0x3f3f3f3f;
    12 
    13 int n, m, s[maxn], t, c;
    14 
    15 struct Edge
    16 {
    17     int from, to, dist;
    18     Edge(int u, int v, int d):from(u), to(v), dist(d) {}
    19 };
    20 
    21 vector<Edge> edges;
    22 vector<int> G[maxn];
    23 
    24 void init()
    25 {
    26     for(int i = 1; i <= n; i++) G[i].clear();
    27     edges.clear();
    28 }
    29 
    30 void AddEdge(int from, int to, int dist)
    31 {
    32     edges.push_back(Edge(from, to, dist));
    33     int sz = edges.size();
    34     G[from].push_back(sz - 1);
    35 }
    36 
    37 int d[maxn];
    38 bool done[maxn];
    39 
    40 void dijkstra()
    41 {
    42     memset(done, false, sizeof(done));
    43     memset(d, 0x3f, sizeof(d));
    44     priority_queue<PII, vector<PII>, greater<PII> > Q;
    45     for(int i = 0; i < c; i++)
    46     {
    47         d[s[i]] = 0;
    48         Q.push(MP(0, s[i]));
    49     }
    50 
    51     while(!Q.empty())
    52     {
    53         PII x = Q.top(); Q.pop();
    54         int u = x.second;
    55         if(done[u]) continue;
    56         done[u] = true;
    57         for(int i = 0; i < G[u].size(); i++)
    58         {
    59             Edge& e = edges[G[u][i]];
    60             int v = e.to;
    61             if(d[v] > d[u] + e.dist)
    62             {
    63                 d[v] = d[u] + e.dist;
    64                 Q.push(MP(d[v], v));
    65             }
    66         }
    67     }
    68 }
    69 
    70 int main()
    71 {
    72     while(scanf("%d%d%d", &n, &m, &t) == 3)
    73     {
    74         init();
    75         for(int i = 0; i < m; i++)
    76         {
    77             int u, v, w;
    78             scanf("%d%d%d", &u, &v, &w);
    79             AddEdge(u, v, w);
    80         }
    81         scanf("%d", &c);
    82         for(int i = 0; i < c; i++) scanf("%d", s + i);
    83         dijkstra();
    84         printf("%d
    ", d[t] == INF ? -1 : d[t]);
    85     }
    86 
    87     return 0;
    88 }
    Dijkstra
     1 #include <cstdio>
     2 #include <cstring>
     3 #include <queue>
     4 #include <vector>
     5 using namespace std;
     6 
     7 const int maxn = 1000 + 10;
     8 const int INF = 0x3f3f3f3f;
     9 
    10 int n, m, s[maxn], t, c;
    11 
    12 struct Edge
    13 {
    14     int from, to, dist;
    15     Edge(int u, int v, int d):from(u), to(v), dist(d) {}
    16 };
    17 
    18 vector<Edge> edges;
    19 vector<int> G[maxn];
    20 
    21 void init()
    22 {
    23     for(int i = 1; i <= n; i++) G[i].clear();
    24     edges.clear();
    25 }
    26 
    27 void AddEdge(int from, int to, int dist)
    28 {
    29     edges.push_back(Edge(from, to, dist));
    30     int sz = edges.size();
    31     G[from].push_back(sz - 1);
    32 }
    33 
    34 int d[maxn];
    35 bool inq[maxn];
    36 
    37 void SPFA()
    38 {
    39     memset(inq, false, sizeof(inq));
    40     memset(d, 0x3f, sizeof(d));
    41     queue<int> Q;
    42     for(int i = 0; i < c; i++)
    43     {
    44         d[s[i]] = 0;
    45         inq[s[i]] = true;
    46         Q.push(s[i]);
    47     }
    48 
    49     while(!Q.empty())
    50     {
    51         int u = Q.front(); Q.pop();
    52         inq[u] = false;
    53         for(int i = 0; i < G[u].size(); i++)
    54         {
    55             Edge& e = edges[G[u][i]];
    56             int v = e.to;
    57             if(d[v] > d[u] + e.dist)
    58             {
    59                 d[v] = d[u] + e.dist;
    60                 if(!inq[v]) { inq[v] = true; Q.push(v); }
    61             }
    62         }
    63     }
    64 }
    65 
    66 int main()
    67 {
    68     while(scanf("%d%d%d", &n, &m, &t) == 3)
    69     {
    70         init();
    71         int u, v, w;
    72         while( m-- ) { scanf("%d%d%d", &u, &v, &w); AddEdge(u, v, w); }
    73         scanf("%d", &c);
    74         for(int i = 0; i < c; i++) scanf("%d", s + i);
    75         SPFA();
    76         printf("%d
    ", d[t] == INF ? -1 : d[t]);
    77     }
    78 
    79     return 0;
    80 }
    SPFA

    2923            Einbahnstrasse                   最短路,Floyd,注意处理好输入格式

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <string>
     5 #include <map>
     6 #include <algorithm>
     7 using namespace std;
     8 
     9 const int maxn = 100 + 10;
    10 
    11 int n, C, m;
    12 int s, cnt[maxn];
    13 int tot;
    14 int d[maxn][maxn];
    15 
    16 map<string, int> id;
    17 
    18 void init()
    19 {
    20     tot = 0;
    21     id.clear();
    22     memset(d, 0x3f, sizeof(d));
    23     memset(cnt, 0, sizeof(cnt));
    24 }
    25 
    26 int ID(string s)
    27 {
    28     if(!id.count(s)) id[s] = tot++;
    29     return id[s];
    30 }
    31 
    32 void floyd()
    33 {
    34     for(int k = 0; k < n; k++)
    35         for(int i = 0; i < n; i++)
    36             for(int j = 0; j < n; j++)
    37                 d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
    38 }
    39 
    40 int main()
    41 {
    42     int kase = 0;
    43 
    44     while(scanf("%d%d%d", &n, &C, &m) == 3)
    45     {
    46         if(!n && !C && !m) break;
    47         init();
    48         string s1, s2, s3;
    49         cin >> s1; s = ID(s1);
    50         for(int i = 0; i < C; i++) { cin >> s1; cnt[ID(s1)]++; }
    51 
    52         for(int i = 0; i < m; i++)
    53         {
    54             cin >> s1 >> s2 >> s3;
    55             int u = ID(s1), v = ID(s3);
    56             int l = s2.length();
    57             int t = 0;
    58             for(int j = 2; j < l - 2; j++) t = t * 10 + (s2[j] - '0');
    59             if(s2[0] == '<') d[v][u] = min(d[v][u], t);
    60             if(s2[l-1] == '>') d[u][v] = min(d[u][v], t);
    61         }
    62 
    63         floyd();
    64 
    65         int ans = 0;
    66         for(int i = 0; i < n; i++) if(cnt[i])
    67             ans += cnt[i] * (d[0][i] + d[i][0]);
    68 
    69         printf("%d. %d
    ", ++kase, ans);
    70     }
    71 
    72     return 0;
    73 }
    Floyd

    3339            In Action                     最短路 + 01背包

    用最短的路径,摧毁多于一半的电力。

    把每个点的最短路径看做体积,每个点的电力看做价值。

    求多于总价值一半的最小背包容量。

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 #include <queue>
      5 #include <vector>
      6 using namespace std;
      7 
      8 const int maxn = 100 + 10;
      9 const int INF = 0x3f3f3f3f;
     10 
     11 int n, m;
     12 int w[maxn];
     13 
     14 struct Edge
     15 {
     16     int from, to, dist;
     17     Edge(int u, int v, int d):from(u), to(v), dist(d) {}
     18 };
     19 
     20 vector<Edge> edges;
     21 vector<int> G[maxn];
     22 int d[maxn];
     23 bool inq[maxn];
     24 
     25 void init()
     26 {
     27     for(int i = 0; i <= n; i++) G[i].clear();
     28     edges.clear();
     29     memset(d, 0x3f, sizeof(d));
     30 }
     31 
     32 void AddEdge(int u, int v, int d)
     33 {
     34     edges.push_back(Edge(u, v, d));
     35     int sz = edges.size();
     36     G[u].push_back(sz - 1);
     37 }
     38 
     39 void SPFA()
     40 {
     41     memset(inq, false, sizeof(inq));
     42     inq[0] = true;
     43     queue<int> Q;
     44     Q.push(0);
     45     d[0] = 0;
     46 
     47     while(!Q.empty())
     48     {
     49         int u = Q.front(); Q.pop();
     50         inq[u] = false;
     51         for(int i = 0; i < G[u].size(); i++)
     52         {
     53             Edge& e = edges[G[u][i]];
     54             int v = e.to;
     55             if(d[v] > d[u] + e.dist)
     56             {
     57                 d[v] = d[u] + e.dist;
     58                 if(!inq[v]) { inq[v] = true; Q.push(v); }
     59             }
     60         }
     61     }
     62 }
     63 
     64 const int maxc = 100000;
     65 int f[maxc];
     66 
     67 int main()
     68 {
     69     int T; scanf("%d", &T);
     70     while( T-- )
     71     {
     72         init();
     73 
     74         scanf("%d%d", &n, &m);
     75         while(m--)
     76         {
     77             int u, v, d;
     78             scanf("%d%d%d", &u, &v, &d);
     79             AddEdge(u, v, d);
     80             AddEdge(v, u, d);
     81         }
     82         SPFA();
     83 
     84         int sumv = 0;
     85         for(int i = 1; i <= n; i++) { scanf("%d", w + i); sumv += w[i]; }
     86         sumv = (sumv >> 1) + 1;
     87 
     88         int sumc = 0, temp = 0;
     89         for(int i = 1; i <= n; i++) if(d[i] < INF) { sumc += d[i]; temp += w[i]; }
     90         if(temp < sumv) { puts("impossible"); continue; }
     91 
     92         //ZeroOnePack
     93         memset(f, 0, sizeof(f));
     94         for(int i = 1; i <= n; i++) if(d[i] < INF)
     95         {
     96             for(int j = sumc; j >= d[i]; j--)
     97                 f[j] = max(f[j], f[j - d[i]] + w[i]);
     98         }
     99         int ans = lower_bound(f, f + sumc, sumv) - f;
    100         printf("%d
    ", ans);
    101     }
    102 
    103     return 0;
    104 }
    SPFA

    2224          The shortest path            双调旅行商问题

    这其实是一道DP,紫书上动态规划那章有这个原题。

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <cmath>
     4 #include <algorithm>
     5 using namespace std;
     6 
     7 struct Point
     8 {
     9     double x, y;
    10     Point(double x = 0, double y = 0):x(x), y(y) {}
    11     bool operator < (const Point& rhs) const { return x < rhs.x; }
    12 };
    13 
    14 const int maxn = 200 + 10;
    15 
    16 int n;
    17 double dis[maxn][maxn], d[maxn][maxn];
    18 Point p[maxn];
    19 
    20 inline double Dist(int i, int j)
    21 {
    22     double dx = p[i].x - p[j].x;
    23     double dy = p[i].y - p[j].y;
    24     return sqrt(dx * dx + dy * dy);
    25 }
    26 
    27 int main()
    28 {
    29     while(scanf("%d", &n) == 1)
    30     {
    31         for(int i = 1; i <= n; i++) scanf("%lf%lf", &p[i].x, &p[i].y);
    32         for(int i = 1; i <= n; i++)
    33         {
    34             dis[i][i] = 0;
    35             for(int j = i + 1; j <= n; j++)
    36                 dis[i][j] = dis[j][i] = Dist(i, j);
    37         }
    38 
    39         memset(d, 0, sizeof(d));
    40         d[2][1] = dis[2][1];
    41         for(int i = n - 1; i > 1; i--)
    42             for(int j = 1; j < i; j++)
    43             {
    44                 if(i == n - 1) d[i][j] = dis[i][n] + dis[j][n];
    45                 else d[i][j] = min(d[i+1][j] + dis[i][i+1], d[i+1][i] + dis[j][i+1]);
    46             }
    47 
    48         printf("%.2f
    ", d[2][1] + dis[2][1]);
    49     }
    50 
    51     return 0;
    52 }
    代码君

    2807          The Shortest Path            矩阵运算 Floyd最短路

    好像没什么难点,直接暴力过的,注意里面都是有向边

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 using namespace std;
     5 
     6 const int maxn = 100;
     7 const int INF = 0x3f3f3f3f;
     8 
     9 typedef int Matrix[maxn][maxn];
    10 
    11 int n, m;
    12 Matrix M[maxn];
    13 int d[maxn][maxn];
    14 
    15 void floyd()
    16 {
    17     for(int k = 0; k < n; k++)
    18         for(int i = 0; i < n; i++)
    19             for(int j = 0; j < n; j++)
    20                 d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
    21 }
    22 
    23 int main()
    24 {
    25     while(scanf("%d%d", &n, &m) == 2)
    26     {
    27         if(n == 0 && m == 0) break;
    28 
    29         memset(d, 0x3f, sizeof(d));
    30 
    31         for(int i = 0; i < n; i++)
    32         {
    33             for(int j = 0; j < m; j++)
    34                 for(int k = 0; k < m; k++)
    35                     scanf("%d", &M[i][j][k]);
    36         }
    37 
    38         for(int i = 0; i < n; i++)
    39         {
    40             for(int j = 0; j < n; j++) if(i != j)
    41             {
    42                 //Matrix Multiplication
    43                 Matrix temp;
    44                 memset(temp, 0, sizeof(temp));
    45                 for(int ii = 0; ii < m; ii++)
    46                     for(int jj = 0; jj < m; jj++)
    47                         for(int kk = 0; kk < m; kk++)
    48                             temp[ii][jj] += M[i][ii][kk] * M[j][kk][jj];
    49 
    50                 for(int k = 0; k < n; k++) if(i != k && j != k)
    51                 {
    52                     bool eq = true;
    53                     for(int r = 0; r < m && eq; r++)
    54                         for(int c = 0; c < m; c++)
    55                             if(temp[r][c] != M[k][r][c]) { eq = false; break; }
    56 
    57                     //Matrix i * j equals k
    58                     if(eq) d[i][k] = 1;
    59                 }
    60             }
    61         }
    62 
    63         floyd();
    64 
    65         int Q; scanf("%d", &Q);
    66         while(Q--)
    67         {
    68             int u, v;
    69             scanf("%d%d", &u, &v);
    70             u--; v--;
    71             if(d[u][v] == INF) puts("Sorry");
    72             else printf("%d
    ", d[u][v]);
    73         }
    74     }
    75 
    76     return 0;
    77 }
    Floyd

    1595            find the longest of the shortest    删掉任意一条边的最长最短路

    先求一遍最短路,然后枚举最短路径上的边,将其删掉再求最短路。

    因为删掉其他边的话,是不影响到终点的最短距离的。

    Dijkstra 436MS

     1 /*
     2     Dijkstra 436MS
     3 */
     4 #include <cstdio>
     5 #include <cstring>
     6 #include <queue>
     7 #include <vector>
     8 #define MP make_pair
     9 using namespace std;
    10 typedef pair<int, int> PII;
    11 
    12 const int maxn = 1000 + 10;
    13 const int INF = 0x3f3f3f3f;
    14 
    15 struct Edge
    16 {
    17     int from, to, dist;
    18     Edge(int u, int v, int d):from(u), to(v), dist(d) {}
    19 };
    20 
    21 int n, m;
    22 
    23 vector<Edge> edges;
    24 vector<int> G[maxn];
    25 vector<int> id;
    26 int d[maxn], p[maxn];
    27 bool done[maxn];
    28 
    29 void init()
    30 {
    31     for(int i = 1; i <= n; i++) G[i].clear();
    32     edges.clear();
    33     id.clear();
    34 }
    35 
    36 void AddEdge(int u, int v, int d)
    37 {
    38     edges.push_back(Edge(u, v, d));
    39     edges.push_back(Edge(v, u, d));
    40     int sz = edges.size();
    41     G[u].push_back(sz - 2);
    42     G[v].push_back(sz - 1);
    43 }
    44 
    45 int dijkstra(int no)
    46 {
    47     priority_queue<PII, vector<PII>, greater<PII> > Q;
    48     memset(d, 0x3f, sizeof(d));
    49     d[1] = 0;
    50     memset(done, false, sizeof(done));
    51     Q.push(MP(0, 1));
    52     if(no == -1) memset(p, 0, sizeof(p));
    53 
    54     while(!Q.empty())
    55     {
    56         PII x = Q.top(); Q.pop();
    57         int u = x.second;
    58         if(done[u]) continue;
    59         done[u] = true;
    60         for(int i = 0; i < G[u].size(); i++)
    61         {
    62             int id = G[u][i];
    63             if(id == no || id == (no ^ 1)) continue;    //This edge is deleted
    64             Edge& e = edges[id];
    65             int v = e.to;
    66             if(d[v] > d[u] + e.dist)
    67             {
    68                 d[v] = d[u] + e.dist;
    69                 if(no < 0) p[v] = id;
    70                 Q.push(MP(d[v], v));
    71             }
    72         }
    73     }
    74     return d[n];
    75 }
    76 
    77 int main()
    78 {
    79     while(scanf("%d%d", &n, &m) == 2)
    80     {
    81         init();
    82 
    83         for(int i = 0; i < m; i++)
    84         {
    85             int u, v, d; scanf("%d%d%d", &u, &v, &d);
    86             AddEdge(u, v, d);
    87         }
    88 
    89         dijkstra(-1);
    90         int id = p[n], ans = 0;
    91         while(id) { ans = max(ans, dijkstra(id)); id = p[edges[id].from]; }
    92 
    93         printf("%d
    ", ans);
    94     }
    95 
    96     return 0;
    97 }
    Dijkstra

    SPFA 826MS

     1 /*
     2     SPFA 826MS
     3 */
     4 #include <cstdio>
     5 #include <cstring>
     6 #include <algorithm>
     7 #include <queue>
     8 #include <vector>
     9 using namespace std;
    10 
    11 const int maxn = 1000 + 10;
    12 
    13 struct Edge
    14 {
    15     int from, to, dist;
    16     Edge(int u, int v, int d):from(u), to(v), dist(d) {}
    17 };
    18 
    19 int n, m;
    20 
    21 vector<Edge> edges;
    22 vector<int> G[maxn];
    23 int d[maxn], p[maxn];
    24 bool inq[maxn];
    25 
    26 void init()
    27 {
    28     for(int i = 1; i <= n; i++) G[i].clear();
    29     edges.clear();
    30 }
    31 
    32 void AddEdge(int u, int v, int d)
    33 {
    34     edges.push_back(Edge(u, v, d));
    35     edges.push_back(Edge(v, u, d));
    36     int sz = edges.size();
    37     G[u].push_back(sz - 2);
    38     G[v].push_back(sz - 1);
    39 }
    40 
    41 int SPFA(int no)
    42 {
    43     memset(inq, false, sizeof(inq));
    44     inq[1] = true;
    45     queue<int> Q;
    46     Q.push(1);
    47     memset(d, 0x3f, sizeof(d));
    48     d[1] = 0;
    49     if(no < 0) memset(p, 0, sizeof(p));
    50 
    51     while(!Q.empty())
    52     {
    53         int u = Q.front(); Q.pop();
    54         inq[u] = false;
    55         for(int i = 0; i < G[u].size(); i++)
    56         {
    57             int id = G[u][i];
    58             if(id == no || id == (no ^ 1)) continue;
    59             Edge& e = edges[id];
    60             int v = e.to;
    61             if(d[v] > d[u] + e.dist)
    62             {
    63                 d[v] = d[u] + e.dist;
    64                 if(no < 0) p[v] = id;
    65                 if(!inq[v]) { inq[v] = true; Q.push(v); }
    66             }
    67         }
    68     }
    69 
    70     return d[n];
    71 }
    72 
    73 int main()
    74 {
    75     while(scanf("%d%d", &n, &m) == 2)
    76     {
    77         init();
    78 
    79         //build graph
    80         while( m-- )
    81         {
    82             int u, v, d;
    83             scanf("%d%d%d", &u, &v, &d);
    84             AddEdge(u, v, d);
    85         }
    86 
    87         SPFA(-1);
    88 
    89         int ans = 0, id = p[n];
    90         while(id) { ans = max(ans, SPFA(id)); id = p[edges[id].from]; }
    91 
    92         printf("%d
    ", ans);
    93     }
    94 
    95     return 0;
    96 }
    SPFA

    3986            Harry Potter and the Final Battle    同上题

    一旦出现到达不了的情况就及时输出。

    Dijkstra 374MS

     1 /*
     2     Dijkstra 374MS
     3     莫名其妙地改了一下第93行代码就AC了
     4 */
     5 
     6 #include <cstdio>
     7 #include <cstring>
     8 #include <queue>
     9 #include <vector>
    10 #define MP make_pair
    11 using namespace std;
    12 typedef pair<int, int> PII;
    13 
    14 const int maxn = 1000 + 10;
    15 const int INF = 0x3f3f3f3f;
    16 
    17 struct Edge
    18 {
    19     int from, to, dist;
    20     Edge(int u, int v, int d):from(u), to(v), dist(d) {}
    21 };
    22 
    23 int n, m;
    24 
    25 vector<Edge> edges;
    26 vector<int> G[maxn];
    27 int d[maxn], p[maxn];
    28 bool done[maxn];
    29 
    30 void init()
    31 {
    32     for(int i = 1; i <= n; i++) G[i].clear();
    33     edges.clear();
    34 }
    35 
    36 void AddEdge(int u, int v, int d)
    37 {
    38     edges.push_back(Edge(u, v, d));
    39     edges.push_back(Edge(v, u, d));
    40     int sz = edges.size();
    41     G[u].push_back(sz - 2);
    42     G[v].push_back(sz - 1);
    43 }
    44 
    45 int dijkstra(int no)
    46 {
    47     priority_queue<PII, vector<PII>, greater<PII> > Q;
    48     memset(d, 0x3f, sizeof(d));
    49     d[1] = 0;
    50     memset(done, false, sizeof(done));
    51     Q.push(MP(0, 1));
    52     if(no == -1) memset(p, -1, sizeof(p));
    53 
    54     while(!Q.empty())
    55     {
    56         PII x = Q.top(); Q.pop();
    57         int u = x.second;
    58         if(done[u]) continue;
    59         done[u] = true;
    60         for(int i = 0; i < G[u].size(); i++)
    61         {
    62             int id = G[u][i];
    63             if(id == no || id == (no ^ 1)) continue;
    64             Edge& e = edges[id];
    65             int v = e.to;
    66             if(d[v] > d[u] + e.dist)
    67             {
    68                 d[v] = d[u] + e.dist;
    69                 if(no < 0) p[v] = id;
    70                 Q.push(MP(d[v], v));
    71             }
    72         }
    73     }
    74     return d[n];
    75 }
    76 
    77 int main()
    78 {
    79     int T; scanf("%d", &T);
    80     while(T--)
    81     {
    82         scanf("%d%d", &n, &m);
    83         init();
    84 
    85         for(int i = 0; i < m; i++)
    86         {
    87             int u, v, d; scanf("%d%d%d", &u, &v, &d);
    88             AddEdge(u, v, d);
    89         }
    90 
    91         int ans = dijkstra(-1);
    92         int id = p[n];
    93         while(ans < INF && id != -1) { ans = max(ans, dijkstra(id)); id = p[edges[id].from]; }
    94 
    95         printf("%d
    ", ans == INF ? -1 : ans);
    96     }
    97 
    98     return 0;
    99 }
    Dijkstra

    SPFA 234MS

     1 /*
     2     SPFA 234MS
     3 */
     4 #include <cstdio>
     5 #include <cstring>
     6 #include <queue>
     7 #include <vector>
     8 #include <algorithm>
     9 using namespace std;
    10 
    11 struct Edge
    12 {
    13     int from, to, dist;
    14     Edge(int u, int v, int d):from(u), to(v), dist(d) {}
    15 };
    16 
    17 const int maxn = 1000 + 10;
    18 const int INF = 0x3f3f3f3f;
    19 
    20 int n, m;
    21 
    22 vector<Edge> edges;
    23 vector<int> G[maxn];
    24 int d[maxn], p[maxn];
    25 bool inq[maxn];
    26 
    27 void init()
    28 {
    29     for(int i = 1; i <= n; i++) G[i].clear();
    30     edges.clear();
    31 }
    32 
    33 void AddEdge(int u, int v, int d)
    34 {
    35     edges.push_back(Edge(u, v, d));
    36     edges.push_back(Edge(v, u, d));
    37     int sz = edges.size();
    38     G[u].push_back(sz - 2);
    39     G[v].push_back(sz - 1);
    40 }
    41 
    42 int SPFA(int no)
    43 {
    44     memset(inq, false, sizeof(inq));
    45     inq[1] = true;
    46     queue<int> Q;
    47     Q.push(1);
    48     memset(d, 0x3f, sizeof(d));
    49     d[1] = 0;
    50     if(no < 0) memset(p, -1, sizeof(p));
    51 
    52     while(!Q.empty())
    53     {
    54         int u = Q.front(); Q.pop();
    55         inq[u] = false;
    56         for(int i = 0; i < G[u].size(); i++)
    57         {
    58             int id = G[u][i];
    59             if(id == no || id == (no ^ 1)) continue;
    60             Edge& e = edges[id];
    61             int v = e.to;
    62             if(d[v] > d[u] + e.dist)
    63             {
    64                 d[v] = d[u] + e.dist;
    65                 if(no < 0) p[v] = id;
    66                 if(!inq[v]) { inq[v] = true; Q.push(v); }
    67             }
    68         }
    69     }
    70     return d[n];
    71 }
    72 
    73 int main()
    74 {
    75     int T; scanf("%d", &T);
    76     while( T-- )
    77     {
    78         scanf("%d%d", &n, &m);
    79         init();
    80 
    81         //build graph
    82         while( m-- )
    83         {
    84             int u, v, d;
    85             scanf("%d%d%d", &u, &v, &d);
    86             AddEdge(u, v, d);
    87         }
    88 
    89         int ans = SPFA(-1);
    90         int id = p[n];
    91         while(ans < INF && id != -1) { ans = max(ans, SPFA(id)); id = p[edges[id].from]; }
    92 
    93         printf("%d
    ", ans == INF ? -1 : ans);
    94     }
    95 
    96     return 0;
    97 }
    SPFA

    1599            find the mincost route            Floyd变体,求最小环

     1 #include <cstdio>
     2 #include <algorithm>
     3 using namespace std;
     4 
     5 const int INF = 100000000;
     6 const int maxn = 100 + 10;
     7 
     8 int n, m;
     9 int d[maxn][maxn], dis[maxn][maxn];
    10 
    11 void floyd()
    12 {
    13     for(int i = 1; i <= n; i++)
    14         for(int j = 1; j <= n; j++)
    15             d[i][j] = dis[i][j];
    16     int ans = INF;
    17     for(int k = 1; k <= n; k++)
    18     {
    19         for(int i = 1; i < k; i++)
    20             for(int j = i + 1; j < k; j++)
    21                 ans = min(ans, d[i][j] + dis[i][k] + dis[k][j]);//INF太大的话这里会溢出!!
    22 
    23         for(int i = 1; i <= n; i++)
    24             for(int j = 1; j <= n; j++)
    25                 d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
    26     }
    27     if(ans == INF) puts("It's impossible.");
    28     else printf("%d
    ", ans);
    29 }
    30 
    31 int main()
    32 {
    33     while(scanf("%d%d", &n, &m) == 2)
    34     {
    35         for(int i = 1; i <= n; i++)
    36             for(int j = 1; j <= n; j++) dis[i][j] = INF;
    37         while( m-- )
    38         {
    39             int u, v, dist;
    40             scanf("%d%d%d", &u, &v, &dist);
    41             if(dist < dis[u][v]) dis[u][v] = dis[v][u] = dist;
    42         }
    43         floyd();
    44     }
    45 
    46     return 0;
    47 }
    Floyd

    1839                Delay Constrained...                二分最小流量 + 最短路(带限制最短路)

      1 #include <cstdio>
      2 #include <vector>
      3 #include <cstring>
      4 #include <algorithm>
      5 #include <map>
      6 #include <queue>
      7 #define MP make_pair
      8 using namespace std;
      9 typedef pair<int, int> PII;
     10 
     11 const int maxn = 10000 + 10;
     12 const int INF = 0x3f3f3f3f;
     13 
     14 struct Edge
     15 {
     16     int from, to, cap, dist;
     17     Edge(int u, int v, int c, int d):from(u), to(v), cap(c), dist(d) {}
     18 };
     19 
     20 int n, m, T;
     21 
     22 vector<Edge> edges;
     23 vector<int> G[maxn];
     24 int d[maxn], p[maxn];
     25 bool done[maxn];
     26 
     27 void init()
     28 {
     29     for(int i = 1; i <= n; i++) G[i].clear();
     30     edges.clear();
     31 }
     32 
     33 void AddEdge(int u, int v, int c, int d)
     34 {
     35     edges.push_back(Edge(u, v, c, d));
     36     edges.push_back(Edge(v, u, c, d));
     37     int sz = edges.size();
     38     G[u].push_back(sz - 2);
     39     G[v].push_back(sz - 1);
     40 }
     41 
     42 bool dijkstra(int C, int& temp)
     43 {
     44     memset(p, -1, sizeof(p));
     45     memset(d, 0x3f, sizeof(d));
     46     d[1] = 0;
     47     priority_queue<PII, vector<PII>, greater<PII> > Q;
     48     Q.push(MP(0, 1));
     49 
     50     while(!Q.empty())
     51     {
     52         PII x = Q.top(); Q.pop();
     53         int u = x.second;
     54         for(int i = 0; i < G[u].size(); i++)
     55         {
     56             Edge& e = edges[G[u][i]];
     57             int v = e.to;
     58             if(e.cap < C) continue;
     59             if(d[v] > d[u] + e.dist)
     60             {
     61                 d[v] = d[u] + e.dist;
     62                 p[v] = G[u][i];
     63                 Q.push(MP(d[v], v));
     64             }
     65         }
     66     }
     67 
     68     temp = INF;
     69     int id = p[n];
     70     while(id != -1) { temp = min(temp, edges[id].cap); id = p[edges[id].from]; }
     71 
     72     return d[n] <= T;
     73 }
     74 
     75 int main()
     76 {
     77     //freopen("in.txt", "r", stdin);
     78 
     79     int test; scanf("%d", &test);
     80     while( test-- )
     81     {
     82         init();
     83         scanf("%d%d%d", &n, &m, &T);
     84         int maxc = 0;
     85         while(m--)
     86         {
     87             int u, v, c, d;
     88             scanf("%d%d%d%d", &u, &v, &c, &d);
     89             maxc = max(maxc, c);
     90             AddEdge(u, v, c, d);
     91         }
     92 
     93         int L = 0, R = maxc;
     94         int temp;
     95         while(L < R)
     96         {
     97             int mid = (L + R) / 2 + 1;
     98             if(dijkstra(mid, temp)) L = temp;
     99             else R = mid - 1;
    100         }
    101         printf("%d
    ", L);
    102     }
    103 
    104     return 0;
    105 }
    Dijkstra

    3631               Shortest Path                   Floyd插点法

    每次新加进来一个点,将其作为中间点作一轮松弛操作

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 #include <vector>
     6 using namespace std;
     7 
     8 const int maxn = 300 + 10;
     9 const int INF = 0x3f3f3f3f;
    10 
    11 int n, m, Q;
    12 int d[maxn][maxn];
    13 bool marked[maxn];
    14 
    15 void init()
    16 {
    17     memset(marked, false, sizeof(marked));
    18     memset(d, 0x3f, sizeof(d));
    19     for(int i = 0; i < n; i++) d[i][i] = 0;
    20 }
    21 
    22 int main()
    23 {
    24     int kase = 0;
    25     while(scanf("%d%d%d", &n, &m, &Q) == 3)
    26     {
    27         if(n == 0 && m == 0 && Q == 0) break;
    28 
    29         if(kase) puts("");
    30         printf("Case %d:
    ", ++kase);
    31 
    32         init();
    33         int op, u, v;
    34         for(int i = 0; i < m; i++)
    35         {
    36             int dist;
    37             scanf("%d%d%d", &u, &v, &dist);
    38             if(d[u][v] > dist) d[u][v] = dist;
    39         }
    40 
    41         while(Q--)
    42         {
    43             scanf("%d%d", &op, &u);
    44 
    45             if(op == 0)
    46             {
    47                 if(marked[u]) { printf("ERROR! At point %d
    ", u); continue; }
    48                 marked[u] = true;
    49 
    50                 for(int i = 0; i < n; i++)
    51                     for(int j = 0; j < n; j++)
    52                         d[i][j] = min(d[i][j], d[i][u] + d[u][j]);
    53             }
    54             else
    55             {
    56                 scanf("%d", &v);
    57                 if(!marked[u] || !marked[v]) { printf("ERROR! At path %d to %d
    ", u, v); continue; }
    58                 if(d[u][v] == INF) { puts("No such path"); continue; }
    59                 printf("%d
    ", d[u][v]);
    60             }
    61         }
    62     }
    63 
    64     return 0;
    65 }
    Floyd

    4114                Disney's FastPass             最短路 + 状压DP

    Floyd预处理一遍两点之间的最短路

    state[S1][S2][u]表示已参观过的景点为S1,已有的门票为S2,当前位置为u的最短时间

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 using namespace std;
      5 
      6 const int maxn = 55;
      7 const int INF = 0x3f3f3f3f;
      8 const int maxS = (1 << 8) + 10;
      9 
     10 int n, m, k;
     11 int ans;
     12 int d[maxn][maxn];
     13 int p[maxn], t[maxn], ft[maxn];
     14 int state[maxn];    //state[S1][S2][u]表示已参观过的景点为S1,已有的门票为S2,当前位置为u
     15 
     16 void init()
     17 {
     18     memset(d, 0x3f, sizeof(d));
     19     for(int i = 0; i < n; i++) d[i][i] = 0;
     20     memset(state, 0, sizeof(state));
     21 }
     22 
     23 void floyd()
     24 {
     25     for(int k = 0; k < n; k++)
     26         for(int i = 0; i < n; i++)
     27             for(int j = 0; j < n; j++)
     28                 d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
     29 }
     30 
     31 int dp[maxS][maxS][maxn];
     32 
     33 void DP()
     34 {
     35     memset(dp, 0x3f, sizeof(dp));
     36     dp[0][0][0] = 0;
     37 
     38     int tot = (1 << k) - 1;
     39     for(int S1 = 0; S1 <= tot; S1++)
     40     {
     41         for(int S2 = 0; S2 <= tot; S2++)
     42         {
     43             for(int u = 0; u < n; u++) if(dp[S1][S2][u] < INF)
     44             {
     45                 int& now = dp[S1][S2][u];   //当前状态
     46                 int v, time;
     47                 for(int i = 0; i < k; i++) if(!(S1 & (1 << i)))
     48                 {//考虑下一次要去的景点
     49                     v = p[i];
     50                     time = d[u][v];
     51                     if(S2 & (1 << i)) time += ft[i];
     52                     else time += t[i];
     53                     int& nxt = dp[S1|(1<<i)][S2|state[v]][v];
     54                     nxt = min(nxt, now + time);
     55                 }
     56 
     57                 for(v = 0; v < n; v++)
     58                 {//下一次可能去的地点,因为只是为了获得门票,所以不用排队进去参观
     59                     time = d[u][v];
     60                     int& nxt = dp[S1][S2|state[v]][v];
     61                     nxt = min(nxt, now + time);
     62                 }
     63             }
     64         }
     65     }
     66 
     67     for(int S2 = 0; S2 <= tot; S2++) ans = min(ans, dp[tot][S2][0]);
     68 }
     69 
     70 int main()
     71 {
     72     int T; scanf("%d", &T);
     73     for(int kase = 1; kase <= T; kase++)
     74     {
     75         init();
     76         scanf("%d%d%d", &n, &m, &k);
     77         //顶点标号从0开始
     78         while(m--)
     79         {
     80             int u, v, dist;
     81             scanf("%d%d%d", &u, &v, &dist);
     82             u--; v--;
     83             d[u][v] = d[v][u] = dist;
     84         }
     85         floyd();
     86 
     87         for(int i = 0; i < k; i++)
     88         {
     89             int num;
     90             scanf("%d%d%d%d", &p[i], &t[i], &ft[i], &num);
     91             p[i]--;
     92             while(num--) { int x; scanf("%d", &x); x--; state[x] |= (1 << i); }
     93         }
     94 
     95         ans = INF;
     96         DP();
     97         printf("Case #%d: %d
    ", kase, ans);
     98     }
     99 
    100     return 0;
    101 }
    代码君

    3832            Earth Hour                        三点连通(斯坦纳树)

    原来这叫斯坦纳树?

    将三个点最为源点,跑三遍最短路。最短的路径上不会有重点,因为有重点的话,那它一定不是最短的。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 #include <cmath>
     6 #include <queue>
     7 using namespace std;
     8 
     9 const int maxn = 200 + 10;
    10 const int INF = 10000000;
    11 
    12 int n;
    13 int dis[maxn][maxn];
    14 double x[maxn], y[maxn], r[maxn];
    15 
    16 bool connect(int i, int j)
    17 {
    18     double dx = x[i] - x[j];
    19     double dy = y[i] - y[j];
    20     double dist = sqrt(dx * dx + dy * dy);
    21     return dist <= r[i] + r[j];
    22 }
    23 
    24 void build_graph()
    25 {
    26     memset(dis, 0, sizeof(dis));
    27     for(int i = 0; i < n; i++)
    28         for(int j = 0; j < i; j++)
    29             dis[i][j] = dis[j][i] = connect(i, j) ? 1 : 0;
    30 }
    31 
    32 int d[3][maxn];
    33 bool inq[maxn];
    34 
    35 void SPFA(int s, int d[])
    36 {
    37     memset(inq, false, sizeof(inq));
    38     inq[s] = true;
    39     for(int i = 0; i < n; i++) d[i] = INF;
    40     d[s] = 0;
    41     queue<int> Q;
    42     Q.push(s);
    43 
    44     while(!Q.empty())
    45     {
    46         int u = Q.front(); Q.pop();
    47         inq[u] = false;
    48         for(int v = 0; v < n; v++) if(dis[u][v])
    49         {
    50             if(d[v] > d[u] + 1)
    51             {
    52                 d[v] = d[u] + 1;
    53                 if(!inq[v]) { inq[v] = true; Q.push(v); }
    54             }
    55         }
    56     }
    57 }
    58 
    59 int main()
    60 {
    61     int T; scanf("%d", &T);
    62     while(T--)
    63     {
    64         scanf("%d", &n);
    65         for(int i = 0; i < n; i++) scanf("%lf%lf%lf", x + i, y + i, r + i);
    66         build_graph();
    67 
    68         for(int s = 0; s < 3; s++) SPFA(s, d[s]);
    69 
    70         int t = INF;
    71         for(int u = 0; u < n; u++) t = min(t, d[0][u] + d[1][u] + d[2][u]);
    72         if(t == INF) { puts("-1"); continue; }
    73         printf("%d
    ", n - t - 1);
    74     }
    75 
    76 
    77     return 0;
    78 }
    SPFA

    3873            Invade the Mars                       Dij变体,带保护的最短路

    要想到达一个点,得先到达保护这个点的所有点。

    好题,极力推荐!

    题解

      1 #include <cstdio>
      2 #include <algorithm>
      3 #include <cstring>
      4 #include <queue>
      5 #include <vector>
      6 #include <map>
      7 #define MP make_pair
      8 using namespace std;
      9 typedef long long LL;
     10 typedef pair<LL, int> PII;
     11 
     12 const int maxn = 3000 + 10;
     13 const LL INF = 0x3f3f3f3f3f3f3f3f;
     14 
     15 int n, m;
     16 int deg[maxn];  //城市x的被保护度
     17 LL time[maxn];  //所有保护x的城市全部被攻占的最早时间
     18 vector<int> pro[maxn];  //城市x所保护的城市
     19 
     20 struct Edge
     21 {
     22     int from, to;
     23     LL dist;
     24     Edge(int u, int v, LL d):from(u), to(v), dist(d) {}
     25 };
     26 
     27 vector<Edge> edges;
     28 vector<int> G[maxn];
     29 
     30 void init()
     31 {
     32     for(int i = 1; i <= n; i++) { G[i].clear(); pro[i].clear(); }
     33     edges.clear();
     34 }
     35 
     36 void AddEdge(int u, int v, LL d)
     37 {
     38     edges.push_back(Edge(u, v, d));
     39     int sz = edges.size();
     40     G[u].push_back(sz - 1);
     41 }
     42 
     43 LL d[maxn];
     44 bool done[maxn];
     45 
     46 void dijkstra()
     47 {
     48     memset(time, 0, sizeof(time));
     49     memset(d, 0x3f, sizeof(d));
     50     d[1] = 0;
     51     memset(done, false, sizeof(done));
     52     priority_queue<PII, vector<PII>, greater<PII> > Q;
     53     Q.push(MP(0LL, 1));
     54 
     55     while(!Q.empty())
     56     {
     57         PII x = Q.top(); Q.pop();
     58         int u = x.second;
     59         if(done[u]) continue;
     60         done[u] = true;
     61 
     62         for(int i = 0; i < pro[u].size(); i++)
     63         {
     64             int v = pro[u][i];
     65             deg[v]--;
     66             time[v] = max(time[v], d[u]);
     67             if(!deg[v] && d[v] < INF)
     68             {
     69                 d[v] = max(d[v], time[v]);
     70                 Q.push(MP(d[v], v));
     71             }
     72         }
     73 
     74         for(int i = 0; i < G[u].size(); i++)
     75         {
     76             Edge& e = edges[G[u][i]];
     77             int v = e.to;
     78             if(d[v] > d[u] + e.dist)
     79             {
     80                 d[v] = max(d[u] + e.dist, time[v]);
     81                 if(!deg[v]) Q.push(MP(d[v], v));
     82             }
     83         }
     84     }
     85 }
     86 
     87 int main()
     88 {
     89     int T; scanf("%d", &T);
     90     while(T--)
     91     {
     92         scanf("%d%d", &n, &m);
     93         init();
     94 
     95         //build graph
     96         while(m--)
     97         {
     98             int u, v;
     99             LL d;
    100             scanf("%d%d%I64d", &u, &v, &d);
    101             AddEdge(u, v, d);
    102         }
    103 
    104         for(int i = 1; i <= n; i++)
    105         {
    106             scanf("%d", deg + i);
    107             int x;
    108             for(int j = 0; j < deg[i]; j++) { scanf("%d", &x); pro[x].push_back(i); }
    109         }
    110 
    111         dijkstra();
    112 
    113         printf("%I64d
    ", d[n]);
    114     }
    115 
    116     return 0;
    117 }
    Dijkstra

    4063               Aircraft                     几何构图 最短路(思路简单,就是代码有点难写)

    两两圆求交点,如果两点之间全部被圆所覆盖,说明两点可达。

    可以先求出线段和圆的所有交点,排个序,然后逐段判断线段是否被某个圆所覆盖。

      1 /*
      2     两两求出圆的交点,然后把这些点构图,求一遍最短路。
      3     两个点可达,当且仅当整个线段都被圆所覆盖。
      4     判断圆能被覆盖,可以求出线段和所有圆的交点,然后排个序,逐段判断。
      5 */
      6 //#define DEBUG
      7 #include <cstdio>
      8 #include <cstring>
      9 #include <algorithm>
     10 #include <cmath>
     11 #include <vector>
     12 #include <queue>
     13 using namespace std;
     14 
     15 const int maxn = 1000;
     16 const double INF = 1e10;
     17 const double eps = 1e-6;
     18 int n, sz;
     19 
     20 int dcmp(double x)
     21 {
     22     if(fabs(x) < eps) return 0;
     23     return x < 0 ? -1 : 1;
     24 }
     25 
     26 struct Point
     27 {
     28     double x, y;
     29     Point(double x = 0, double y = 0):x(x), y(y) {}
     30 };
     31 
     32 typedef Point Vector;
     33 
     34 Point operator + (const Point& A, const Point& B)
     35 { return Point(A.x + B.x, A.y + B.y); }
     36 
     37 Point operator - (Point A, Point B)
     38 { return Point(A.x - B.x, A.y - B.y); }
     39 
     40 Point operator * (const Point& A, double p)
     41 { return Point(A.x * p, A.y * p); }
     42 
     43 Point operator / (const Point& A, double p)
     44 { return Point(A.x / p, A.y / p); }
     45 
     46 bool operator < (const Point& A, const Point& B)
     47 { return A.x < B.x || (A.x == B.x && A.y < B.y); }
     48 
     49 bool operator == (const Point& A, const Point& B)
     50 { return dcmp(A.x - B.x) == 0 && dcmp(A.y - B.y) == 0; }
     51 
     52 double Dot(Vector A, Vector B)
     53 { return A.x * B.x + A.y * B.y; }
     54 
     55 double Length(Vector A)
     56 {
     57     return sqrt(A.x*A.x + A.y*A.y);
     58 }
     59 
     60 double angle(Vector A)
     61 { return atan2(A.y, A.x); }
     62 
     63 struct Circle
     64 {
     65     Point c;
     66     double r;
     67 
     68     Circle() {}
     69     Circle(Point c, double r):c(c), r(r) {}
     70 
     71     Point point(double ang)
     72     { return Point(c.x + r * cos(ang), c.y + r * sin(ang)); }
     73 
     74 }circles[maxn];
     75 
     76 struct Line
     77 {
     78     Point p;
     79     Vector v;
     80     double ang;
     81 
     82     Line() {}
     83     Line(Point p, Vector v):p(p), v(v) { ang = atan2(v.y, v.x); }
     84 
     85     Point point(double t) { return p + v * t; }
     86 
     87 };
     88 
     89 void getCircleCircleIntersection(Circle C1, Circle C2, vector<Point>& sol)
     90 {//求圆和圆的交点
     91     double d = Length(C1.c - C2.c);
     92 
     93     if(dcmp(d) == 0) return;
     94     if(dcmp(C1.r + C2.r - d) < 0) return;
     95     if(dcmp(fabs(C1.r - C2.r) - d) > 0) return;
     96 
     97     double a = angle(C2.c - C1.c);
     98     double da = acos((C1.r*C1.r + d*d - C2.r*C2.r) / (2.0 * C1.r * d));
     99     Point p1 = C1.point(a + da), p2 = C1.point(a - da);
    100     sol.push_back(p1);
    101     if(p1 == p2) return;
    102     sol.push_back(p2);
    103 }
    104 
    105 void getCircleLineIntersection(Line L, Circle C, vector<Point>& sol)
    106 {//求线段和圆的交点
    107     double a = L.v.x, b = L.p.x - C.c.x, c = L.v.y, d = L.p.y - C.c.y;
    108     double e = a*a + c*c, f = 2.0*(a*b + c*d), g = b*b + d*d - C.r*C.r;
    109     double delta = f*f - 4.0*e*g;
    110 
    111     if(dcmp(delta) < 0) return;
    112 
    113     if(dcmp(delta) == 0)
    114     {
    115         double t = -f / (2.0 * e);
    116         if(dcmp(t) >= 0 && dcmp(t - 1) <= 0)
    117             sol.push_back(L.point(t));
    118     }
    119 
    120     double t1 = (-f - sqrt(delta)) / (2 * e);
    121     if(dcmp(t1) >= 0 && dcmp(t1 - 1) <= 0)
    122         sol.push_back(L.point(t1));
    123 
    124     double t2 = (-f + sqrt(delta)) / (2 * e);
    125     if(dcmp(t2) >= 0 && dcmp(t2 - 1) <= 0)
    126         sol.push_back(L.point(t2));
    127 }
    128 
    129 vector<Point> p;
    130 
    131 bool SegmentInCircle(const Point& A, const Point& B)
    132 {//线段在圆内,也就是两个端点都要在某个圆内
    133     bool ok = false;
    134     for(int i = 0; i < n; i++)
    135     {
    136         Circle& C = circles[i];
    137         if(dcmp(Length(A - C.c) - C.r) <= 0
    138            && dcmp(Length(B - C.c) - C.r) <= 0)
    139         {
    140             ok = true;
    141             break;
    142         }
    143     }
    144     return ok;
    145 }
    146 
    147 bool SegmentBeCoverd(Point A, Point B)
    148 {//判断这条路线能否走通,写就是整条线段都被若干个圆所覆盖
    149     vector<Point> inter;
    150     inter.push_back(A);
    151     inter.push_back(B);
    152     Line L(A, B - A);
    153     for(int i = 0; i < n; i++)
    154         getCircleLineIntersection(L, circles[i], inter);
    155 
    156     sort(inter.begin(), inter.end());
    157 
    158     int sz = inter.size();
    159     for(int i = 0; i < sz - 1; i++)
    160         if(!SegmentInCircle(inter[i], inter[i + 1]))
    161             return false;
    162 
    163     return true;
    164 }
    165 
    166 struct Edge
    167 {
    168     int from, to;
    169     double dist;
    170     Edge(int u, int v, double d):from(u), to(v), dist(d) {}
    171 };
    172 
    173 vector<Edge> edges;
    174 vector<int> G[maxn];
    175 
    176 void init()
    177 {
    178     p.clear();
    179     edges.clear();
    180     for(int i = 0; i < sz; i++) G[i].clear();
    181 }
    182 
    183 void AddEdge(int u, int v, double d)
    184 {
    185     edges.push_back(Edge(u, v, d));
    186     edges.push_back(Edge(v, u, d));
    187     int sz = edges.size();
    188     G[u].push_back(sz - 2);
    189     G[v].push_back(sz - 1);
    190 }
    191 
    192 double d[maxn];
    193 bool inq[maxn];
    194 
    195 void SPFA()
    196 {
    197     for(int i = 0; i < sz; i++) d[i] = INF;
    198     d[0] = 0;
    199     memset(inq, false, sizeof(inq));
    200     inq[0] = true;
    201     queue<int> Q;
    202     Q.push(0);
    203 
    204     while(!Q.empty())
    205     {
    206         int u = Q.front(); Q.pop();
    207         inq[u] = false;
    208         for(int i = 0; i < G[u].size(); i++)
    209         {
    210             Edge& e = edges[G[u][i]];
    211             int v = e.to;
    212             if(d[v] > d[u] + e.dist)
    213             {
    214                 d[v] = d[u] + e.dist;
    215                 if(!inq[v]) { inq[v] = true; Q.push(v); }
    216             }
    217         }
    218     }
    219 }
    220 
    221 int main()
    222 {
    223     int T; scanf("%d", &T);
    224     for(int kase = 1; kase <= T; kase++)
    225     {
    226         scanf("%d", &n);
    227 
    228         init();
    229 
    230         for(int i = 0; i < n; i++)
    231         {
    232             double x, y, r;
    233             scanf("%lf%lf%lf", &x, &y, &r);
    234             Point p(x, y);
    235             circles[i] = Circle(p, r);
    236         }
    237 
    238         p.push_back(circles[0].c);
    239         p.push_back(circles[n - 1].c);
    240 
    241         for(int i = 0; i < n; i++)
    242             for(int j = 0; j < i; j++)
    243                 getCircleCircleIntersection(circles[i], circles[j], p);
    244         sz = p.size();
    245 
    246         for(int i = 0; i < sz; i++)
    247         {
    248             for(int j = 0; j < i; j++)
    249             {
    250                 double d = Length(p[i] - p[j]);
    251 
    252                 if(SegmentBeCoverd(p[i], p[j]))
    253                     AddEdge(i, j, d);
    254             }
    255         }
    256 
    257         SPFA();
    258 
    259         printf("Case %d: ", kase);
    260         if(dcmp(d[1] == INF)) puts("No such path.");
    261         else printf("%.4f
    ", d[1]);
    262     }
    263 
    264     return 0;
    265 }
    代码君

    hdu4179          Difficult Routes               带限制最短路

    建一个正图和反图,分别求出源点到各点的最短距离,和各点到源点的最短距离。

    枚举难度为d的边,求最小值。

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 #include <queue>
      5 #include <vector>
      6 #include <cmath>
      7 using namespace std;
      8 
      9 const int maxn = 10000 + 10;
     10 const int maxm = 30000 + 10;
     11 const double INF = 1e8;
     12 const double eps = 1e-6;
     13 
     14 int dcmp(double x)
     15 {
     16     if(fabs(x) < eps) return 0;
     17     return x < 0 ? -1 : 1;
     18 }
     19 
     20 int n, m, s, t, D;
     21 
     22 int u[maxm], v[maxm];
     23 double x[maxn], y[maxn], z[maxn];
     24 vector<int> eq;
     25 
     26 struct Edge
     27 {
     28     int from, to;
     29     double dist;
     30     Edge(int u, int v, double d):from(u), to(v), dist(d) {}
     31 };
     32 
     33 vector<Edge> edges[2];
     34 vector<int> G[2][maxn];
     35 
     36 void init()
     37 {
     38     for(int i = 1; i <= n; i++) { G[0][i].clear(); G[1][i].clear(); }
     39     edges[0].clear();
     40     edges[1].clear();
     41 }
     42 
     43 void AddEdge(int num, int u, int v, double d)
     44 {
     45     edges[num].push_back(Edge(u, v, d));
     46     int sz = edges[num].size();
     47     G[num][u].push_back(sz - 1);
     48 }
     49 
     50 void Dist(int u, int v, double& run, double& d)
     51 {
     52     double dx = x[u] - x[v];
     53     double dy = y[u] - y[v];
     54     double dz = z[u] - z[v];
     55     d = sqrt(dx*dx + dy*dy + dz*dz);
     56     run = sqrt(dx*dx + dy*dy);
     57 }
     58 
     59 inline int Difficulty(int u, int v, double run)
     60 {
     61     if(z[u] >= z[v]) return 0;
     62     return (int) floor(100.0 * (z[v] - z[u]) / run);
     63 }
     64 
     65 double ds[maxn], dt[maxn];
     66 bool inq[maxn];
     67 
     68 void SPFA(int num, int s, double d[])
     69 {
     70     for(int i = 1; i <= n; i++) d[i] = INF;
     71     d[s] = 0;
     72     memset(inq, false, sizeof(inq));
     73     inq[s] = true;
     74     queue<int> Q;
     75     Q.push(s);
     76 
     77     while(!Q.empty())
     78     {
     79         int u = Q.front(); Q.pop();
     80         inq[u] = false;
     81         for(int i = 0; i < G[num][u].size(); i++)
     82         {
     83             Edge& e = edges[num][G[num][u][i]];
     84             int v = e.to;
     85             if(d[v] > d[u] + e.dist)
     86             {
     87                 d[v] = d[u] + e.dist;
     88                 if(!inq[v]) { inq[v] = true; Q.push(v); }
     89             }
     90         }
     91     }
     92 }
     93 
     94 int main()
     95 {
     96     //freopen("in.txt", "r", stdin);
     97 
     98     while(scanf("%d%d", &n, &m) == 2)
     99     {
    100         if(n == 0 && m == 0) break;
    101 
    102         for(int i = 1; i <= n; i++) scanf("%lf%lf%lf", x + i, y + i, z + i);
    103         for(int i = 1; i <= m; i++) scanf("%d%d", u + i, v + i);
    104         scanf("%d%d%d", &s, &t, &D);
    105 
    106         init();
    107         eq.clear();
    108         for(int i = 1; i <= m; i++)
    109         {
    110             double run, d;
    111             Dist(u[i], v[i], run, d);
    112 
    113             int diffi = Difficulty(u[i], v[i], run);
    114             if(diffi <= D)
    115             {
    116                 AddEdge(0, u[i], v[i], d);
    117                 AddEdge(1, v[i], u[i], d);
    118                 if(diffi == D) { int sz = edges[0].size(); eq.push_back(sz - 1); }
    119             }
    120 
    121             diffi = Difficulty(v[i], u[i], run);
    122             if(diffi <= D)
    123             {
    124                 AddEdge(0, v[i], u[i], d);
    125                 AddEdge(1, u[i], v[i], d);
    126                 if(diffi == D) { int sz = edges[0].size(); eq.push_back(sz - 1); }
    127             }
    128         }
    129 
    130         SPFA(0, s, ds);
    131         SPFA(1, t, dt);
    132 
    133         double ans = INF;
    134         for(int i = 0; i < eq.size(); i++)
    135         {
    136             Edge& e = edges[0][eq[i]];
    137             int u = e.from, v = e.to;
    138             ans = min(ans, ds[u] + e.dist + dt[v]);
    139         }
    140 
    141         if(dcmp(ans - INF) == 0) puts("None");
    142         else printf("%.1f
    ", ans);
    143     }
    144 
    145     return 0;
    146 }
    SPFA

    待续……

  • 相关阅读:
    git使用
    javascript关于事件与闭包
    Ajax和跨域
    通过触发器进行的操作
    30分钟学会jquery插件
    那些年用过的jquery插件
    网页设计常用网页技巧
    XML操作
    效果A:浏览器跳转以及判断来路客户信息
    数据库
  • 原文地址:https://www.cnblogs.com/chdacm/p/4574675.html
Copyright © 2020-2023  润新知