zoukankan      html  css  js  c++  java
  • ACM/ICPC 之 最短路径-Bellman Ford范例(POJ1556-POJ2240)

      两道Bellman Ford解最短路的范例,Bellman Ford只是一种最短路的方法,两道都可以用dijkstra, SPFA做。

      Bellman Ford解法是将每条边遍历一次,遍历一次所有边可以求得一点到任意一点经过一条边的最短路,遍历两次可以求得一点到任意一点经过两条边的最短路...如 此反复,当遍历m次所有边后,则可以求得一点到任意一点经过m条边后的最短路(有点类似离散数学中邻接矩阵的连通性判定)


    POJ1556-The Doors

      初学就先看POJ2240吧

      题意:求从(0,5)到(10,5)的最短折线距离,中间会给最多十八道墙。

      题解:本题设计简单的计算几何知识和最短路的知识,读完题后要将墙的端点看做一个坐标,先求出所有的可行边,然后做一次最短路就可以了

     1 // 2 //POJ1556-ZOJ1721
     3 //简单几何+最短路
     4 //Time:0Ms    Memory:204K
     5 #include<iostream>
     6 #include<cstring>
     7 #include<cstdio>
     8 #include<algorithm>
     9 #include<cmath>
    10 using namespace std;
    11 #define INF 0x7f7f7f7f
    12 #define MAX 20*5
    13 #define POW2(x) ((x)*(x))
    14 #define DIS(i,j) sqrt(POW2(i.x - j.x) + POW2(i.y - j.y))
    15 #define P(i,j) (4*i+j)    //第i组第j个点的序列号
    16 struct Point {
    17     double x, y;
    18 }p[MAX];
    19 struct Edge {
    20     int u, v;
    21     double d;
    22 }e[MAX*MAX];
    23 int n, m;
    24 double d[MAX];
    25 int en;    //edge_num
    26 //判断两点是否能在maxn组点内连通
    27 bool access(Point p1, Point p2, int maxn)
    28 {
    29     for (int i = 0; i < maxn; i++)
    30         if (p[P(i, 1)].x > p1.x && p[P(i, 1)].x < p2.x)    //该组点在两点之间
    31         {
    32             //算出线段在该横坐标下的纵坐标
    33             double y = (p1.y - p2.y) / (p2.x - p1.x) * (p2.x - p[P(i, 1)].x) + p2.y;
    34             if (y > p[P(i, 4)].y || y < p[P(i, 1)].y || (y > p[P(i, 2)].y && y < p[P(i, 3)].y))    //相交
    35                 return false;
    36         }
    37     return true;
    38 }
    39 //记录x组第y个点作为终点的线段
    40 void add(int x, int y)
    41 {
    42     for (int k = 0; k <= 4 * x; k++)
    43         if (access(p[k], p[P(x, y)], x)) {
    44             e[en].u = k;
    45             e[en].v = P(x, y);
    46             e[en++].d = DIS(p[e[en].u], p[e[en].v]);
    47         }
    48 }
    49 void bellman_ford(int x)
    50 {
    51     memset(d, INF, sizeof(d));
    52     d[0] = 0;
    53     for (int i = 0; i <= n; i++)    //扩展n+1次
    54         for (int j = 0; j < en; j++)    //遍历每条边
    55             d[e[j].v] = min(d[e[j].u] + e[j].d, d[e[j].v]);
    56 }
    57 int main()
    58 {
    59     //起点
    60     p[0].x = 0;
    61     p[0].y = 5;
    62     while (scanf("%d", &n), n != -1)
    63     {
    64         en = 0;    //Init
    65         double x, y;
    66         for (int i = 0; i < n; i++)
    67         {
    68             scanf("%lf", &x);
    69             for (int j = 1; j <= 4; j++)
    70             {
    71                 scanf("%lf", &y);
    72                 p[P(i,j)].x = x;
    73                 p[P(i,j)].y = y;
    74                 add(i, j);
    75             }
    76         }
    77         //终点
    78         p[P(n, 1)].x = 10;
    79         p[P(n, 1)].y = 5;
    80         add(n, 1);
    81         
    82         bellman_ford(0);
    83         printf("%.2f
    ", d[P(n, 1)]);
    84     }
    85     
    86     return 0;
    87 }

    POJ2240-Arbitrage

      题意:从一种货币A经过多次转换后可以得到更多的货币A,则称为套汇,求给定货币转换语句,判断是否存在套汇。

      题解:将货币看做结点,转换比率看做路长(乘积关系),建立一个图模型就可以知道实际上是在求是否存在最长路的路长超过1。

     1 //套汇
     2 //POJ2240-ZOJ1092
     3 //求最长路(乘积) - 回路 路长 > 1 则为套汇
     4 //Time:63Ms    Memory:200K
     5 #include<iostream>
     6 #include<cstring>
     7 #include<cstdio>
     8 #include<algorithm>
     9 using namespace std;
    10 #define MAX 32
    11 #define MAXS 20
    12 struct Edge {
    13     int u, v;
    14     double d;
    15 }e[MAX*MAX];
    16 int n, m;
    17 char city[MAX][MAXS];
    18 double d[MAX];    //到某一点的最长路
    19 int find(char s[MAXS])
    20 {
    21     for (int i = 0; i < n;i++)
    22         if (!strcmp(s, city[i]))    return i;
    23     return -1;
    24 }
    25 //是否套汇
    26 bool bellman_ford(int x)
    27 {
    28     memset(d, 0, sizeof(d));
    29     d[x] = 1;
    30     for (int i = 1; i <= n; i++)    //最多经过n条边回到x(若更多次变更也只能是套汇)
    31         for (int j = 0; j < m; j++)
    32         {
    33             d[e[j].v] = max(d[e[j].u] * e[j].d, d[e[j].v]);
    34             if (d[x] > 1) return true;
    35         }
    36     return false;
    37 }
    38 int main()
    39 {
    40     int cas = 1;
    41     while (scanf("%d", &n), n)
    42     {
    43         for (int i = 0; i < n; i++)
    44             scanf("%s", city[i]);
    45         scanf("%d", &m);
    46         for (int i = 0; i < m; i++)
    47         {
    48             char s1[MAXS], s2[MAXS];
    49             double dis;
    50             scanf("%s%lf%s", s1, &dis, s2);
    51             e[i].u = find(s1);
    52             e[i].v = find(s2);
    53             e[i].d = dis;
    54         }
    55         
    56         bool flag = false;
    57         for (int i = 0; i < n; i++)
    58         {
    59             if (bellman_ford(i)) {
    60                 flag = true;
    61                 break;
    62             }
    63         }
    64         if (flag == true)
    65             printf("Case %d: Yes
    ", cas++);
    66         else printf("Case %d: No
    ", cas++);
    67     }
    68     return 0;
    69 }
  • 相关阅读:
    div设置参数contenteditable=true
    Html事件总结
    PHP的isset()和empty()比较
    jQuery的ajax和遍历数组json代码
    PHP获取域名的几个函数使用
    关于网站favicon.ico
    PROCEDURE ANALYSE 通过分析select查询结果
    mysql 存在更新 不存在插入
    MySQL Migration Toolkit的使用
    高性能MySQL读书笔记:找出谁持有锁
  • 原文地址:https://www.cnblogs.com/Inkblots/p/5456754.html
Copyright © 2011-2022 走看看