zoukankan      html  css  js  c++  java
  • 大白叔叔专题之最短路、最小生成树(二)

    1、uva 11374 Airport Express

      题意:给出若干经济舱的路线和商务舱的路线,但只能选择乘坐一次商务舱。求前往机场的最短时间。

      思路:分别从起点和终点求出到其他点的最短路,枚举每个商务舱,记录最小值。

      1 #include<iostream>
      2 #include<vector>
      3 #include<queue>
      4 #include<cstring>
      5 #include<algorithm>
      6 #include<cstdio>
      7 using namespace std;
      8 const int maxn = 510;
      9 const int INF = 0x3f3f3f3f;
     10 struct edge
     11 {
     12     int from, to, cost,next;
     13     edge(int ff=0,int tt=0,int cc=0,int nn=0):from(ff),to(tt),cost(cc),next(nn){ }
     14 };
     15 vector<edge>Edge;
     16 int Head[maxn], totedge;
     17 int N, S, E;
     18 int M, K;
     19 struct DIJ
     20 {
     21     bool vis[maxn];
     22     int preS[maxn];
     23     int disS[maxn];
     24     int disT[maxn];
     25     int preT[maxn];
     26     int st, ed,n;
     27     void set(int nodes,int source,int dest)
     28     {
     29         n=nodes,st = source, ed = dest;
     30     }
     31     void Init()
     32     {
     33         memset(Head, -1, sizeof(Head));
     34         totedge = 0;
     35         Edge.clear();
     36     }
     37     void addedge(int from, int to, int cost)
     38     {
     39         Edge.push_back(edge(from, to, cost, Head[from]));
     40         Head[from] = totedge++;
     41         Edge.push_back(edge(to, from, cost, Head[to]));
     42         Head[to] = totedge++;
     43     }
     44     void cal_dij(int *dis,int *pre)
     45     {
     46         memset(vis, 0, sizeof(vis));
     47         for (int i = 1; i <= n; i++) dis[i] = INF,pre[i]=-1;
     48         for (int i = Head[st]; i != -1; i = Edge[i].next)
     49         {
     50             dis[Edge[i].to] = Edge[i].cost;
     51             pre[Edge[i].to] = st;
     52         }
     53         vis[st] = true, dis[st] = 0;
     54         for (int i = 1; i < n; i++)
     55         {
     56             int u = st, Min = INF;
     57             for (int j = 1; j <= n; j++)
     58             {
     59                 if (!vis[j] && dis[j] < Min) u = j, Min = dis[j];
     60             }
     61             vis[u] = true;
     62             for (int k = Head[u]; k != -1; k = Edge[k].next)
     63             {
     64                 int v = Edge[k].to;
     65                 if (!vis[v] && dis[v] > dis[u] + Edge[k].cost)
     66                 {
     67                     dis[v] = dis[u] + Edge[k].cost;
     68                     pre[v] = u;
     69                 }
     70             }
     71         }
     72     }
     73     void PrintS(int u)
     74     {
     75         if (u != S) PrintS(preS[u]);
     76         if (u == S) printf("%d",u);
     77         else printf(" %d", u);
     78     }
     79     void PrintT(int u)
     80     {
     81         printf(" %d", u);
     82         if(u!=E) PrintT(preT[u]);
     83     }
     84 }dij;
     85 
     86 int main()
     87 {
     88     int Case = 1;
     89     while (~scanf("%d%d%d", &N, &S, &E))
     90     {
     91         if (Case > 1) printf("
    ");
     92         scanf("%d", &M);
     93         dij.Init();
     94         for (int i = 1; i <= M; i++)
     95         {
     96             int u, v, c;
     97             scanf("%d%d%d", &u, &v, &c);
     98             dij.addedge(u, v, c);
     99         }
    100         dij.set(N, S, E);
    101         dij.cal_dij(dij.disS,dij.preS);
    102         dij.set(N, E, S);
    103         dij.cal_dij(dij.disT,dij.preT);
    104         scanf("%d", &K);
    105         int ans = dij.disS[E],from,to;
    106         for(int i=1;i<=K;i++)
    107         {
    108             int u, v, c;
    109             scanf("%d%d%d", &u, &v, &c);
    110             if (dij.disS[u] + dij.disT[v] + c < ans) ans = dij.disS[u] + dij.disT[v] + c, from = u, to = v;
    111             if (dij.disS[v] + dij.disT[u] + c < ans) ans = dij.disS[v] + dij.disT[u] + c, from = v, to = u;
    112         }
    113         if (ans == dij.disS[E])
    114         {
    115             dij.PrintS(E);
    116             printf("
    ");
    117             printf("Ticket Not Used
    ");
    118             printf("%d
    ", ans);
    119         }
    120         else
    121         {
    122             dij.PrintS(from);
    123             dij.PrintT(to);
    124             printf("
    ");
    125             printf("%d
    ", from);
    126             printf("%d
    ", ans);
    127         }
    128         Case++;
    129     }
    130     return 0;
    131 }
    View Code

     2、uva 10917 Walk Through the Forest

      题意:办公室在1,家在2.现在需要从办公室回到家,途中会穿过森林中的n-2个结点。给出无向图,如果当前位置再结点u,存在从u-->v的边并且v到家的最短距离小于u到家的距离,则可以从u走到v.现在求所有的方案数。

      思路:先求出所有的点到家的最短距离。然后用dfs得到方案数(类似深搜一棵有根外向树)。

      1 #include<iostream>
      2 #include<queue>
      3 #include<cstring>
      4 #include<cstdio>
      5 #include<vector>
      6 using namespace std;
      7 const int maxn = 1100;
      8 const int INF = 0x3f3f3f3f;
      9 struct edge
     10 {
     11     int from, to, cap,next;
     12     edge(int ff=0,int tt=0,int cc=0,int nn=0):from(ff),to(tt),cap(cc),next(nn){ }
     13 };
     14 vector<edge>Edge;
     15 int Head[maxn], totedge;
     16 struct SPFA
     17 {
     18     int n, st, ed;
     19     int vis[maxn];
     20     int dis[maxn];
     21     int cnt[maxn];
     22     int pre[maxn];
     23     void Init()
     24     {
     25         memset(Head, -1, sizeof(Head));
     26         totedge = 0;
     27         Edge.clear();
     28     }
     29     void set(int nodes, int source, int dest)
     30     {
     31         n = nodes, st = source, ed = dest;
     32     }
     33     void addedge(int from, int to, int cap)
     34     {
     35         Edge.push_back(edge(from, to, cap, Head[from]));
     36         Head[from] = totedge++;
     37         Edge.push_back(edge(to, from, cap, Head[to]));
     38         Head[to] = totedge++;
     39     }
     40     bool cal_spfa()
     41     {
     42         memset(vis, 0, sizeof(vis));
     43         memset(dis, INF, sizeof(dis));
     44         memset(cnt, 0,sizeof(cnt));
     45         memset(pre, -1, sizeof(pre));
     46 
     47         vis[st] = true, cnt[st]++, dis[st] = 0;
     48         queue<int>q;
     49         q.push(st);
     50         while (!q.empty())
     51         {
     52             int u = q.front();
     53             q.pop();
     54             vis[u] = false;
     55 
     56             for (int i = Head[u]; i != -1; i = Edge[i].next)
     57             {
     58                 int v = Edge[i].to;
     59                 if (dis[v] > dis[u] + Edge[i].cap)
     60                 {
     61                     dis[v] = dis[u] + Edge[i].cap;
     62                     pre[v] = u;
     63                     if (!vis[v])
     64                     {
     65                         vis[v] = true;
     66                         q.push(v);
     67                         cnt[v]++;
     68                         if (v > n)return false;
     69                     }
     70                 }
     71             }
     72         }
     73         return true;
     74     }
     75 }spfa;
     76 int n,m;
     77 int Count[maxn];
     78 int dfs(int u)
     79 {
     80     if (Count[u] != 0) return Count[u];
     81     for (int i = Head[u]; i != -1; i = Edge[i].next)
     82     {
     83         int v = Edge[i].to;
     84         if (spfa.dis[v]<spfa.dis[u])
     85         {
     86             int tmp = dfs(v);
     87             Count[u] += tmp;
     88         }
     89     }
     90     return Count[u];
     91 }
     92 int main()
     93 {
     94     while (~scanf("%d", &n) && n)
     95     {
     96         int from, to, d;
     97         spfa.Init();
     98         scanf("%d", &m);
     99         for (int i = 1; i <= m; i++)
    100         {
    101             scanf("%d%d%d", &from, &to, &d);
    102             spfa.addedge(from, to, d);
    103         }
    104         spfa.set(n, 2, 1);
    105         spfa.cal_spfa();
    106         memset(Count, 0, sizeof(Count));
    107         Count[2] = 1;
    108         int ans = dfs(1);
    109         printf("%d
    ", ans);
    110     }
    111     return 0;
    112 }
    View Code

    3、uva 10537 The Toll! Revisited

      题意:现在要求运到目的地时要有若干货物。从一个地方离开不需要缴纳费用,但进入一个地方时,需要缴纳费用,如果是village(小写字母表示),只需缴纳一个货物作为费用;如果是town(大写字母表示),每20个货物需要缴纳1个货物作为费用。问出发时最少需要的货物,并给出字典序最小的路径。

      思路:因为边的费用和带的货物的数目有关,逆向求解,如果逆向从u到若干其他结点,需要考虑u是viliage还是town,前者为dis[u]+1,后者为ceil(dis[u]*20.0/19.0).然后记录路径前驱,方便输出。

      1 #include<iostream>
      2 #include<algorithm>
      3 #include<queue>
      4 #include<vector>
      5 #include<cstring>
      6 #include<cctype>
      7 #include<cmath>
      8 using namespace std;
      9 const int maxn = 110;
     10 const long long INF = (long long)1<<61;
     11 struct edge
     12 {
     13     int from, to, next;
     14     edge(int ff=0,int tt=0,int nn=0):from(ff),to(tt),next(nn){ }
     15 };
     16 vector<edge>Edge;
     17 int Head[maxn], totedge;
     18 
     19 struct SPFA
     20 {
     21     int n, st, ed;
     22     long long dis[maxn];
     23     int cnt[maxn];
     24     int vis[maxn];
     25     int pre[maxn];
     26 
     27     void Init()
     28     {
     29         memset(Head, -1, sizeof(Head));
     30         totedge = 0;
     31         Edge.clear();
     32     }
     33     void set(int nodes, int source, int dest)
     34     {
     35         n = nodes, st = source, ed = dest;
     36     }
     37     void addedge(int from, int to)
     38     {
     39         Edge.push_back(edge(from, to, Head[from]));
     40         Head[from] = totedge++;
     41         Edge.push_back(edge(to, from, Head[to]));
     42         Head[to] = totedge++;
     43     }
     44     bool cal_spfa(int desnum)
     45     {
     46         memset(vis, 0, sizeof(vis));
     47         memset(dis, 0x3f, sizeof(dis));
     48         memset(pre, -1, sizeof(pre));
     49         memset(cnt, 0, sizeof(cnt));
     50         queue<int>q;
     51         q.push(ed);
     52         vis[ed] = true, dis[ed] = desnum;
     53         while (!q.empty())
     54         {
     55             int u = q.front();
     56             q.pop();
     57             vis[u] = false;
     58             long long  c;
     59             if (u >= 26)
     60             {
     61                 c = (long long)ceil(dis[u]*1.0/19.0);
     62                 //c = (long long)ceil(double(dis[u])*20.0 / 19.0) - dis[u];
     63             }
     64             else c = 1;
     65             for (int i = Head[u]; i != -1; i = Edge[i].next)
     66             {
     67                 int v = Edge[i].to;
     68                 if (dis[v] > dis[u] + c)
     69                 {
     70                     dis[v] = dis[u] + c;
     71                     pre[v] = u;
     72                     if (!vis[v])
     73                     {
     74                         q.push(v);
     75                         vis[v] = true;
     76                         cnt[v]++;
     77                     }
     78                 }
     79                 else if (dis[v] == dis[u] + c)
     80                 {
     81                     if (u > pre[v]&&u>=26&&pre[v]<26) pre[v] = u;
     82                     else if (u < pre[v]&&pre[v]<26) pre[v] = u;
     83                     else if(u<pre[v]&&u>=26)pre[v] = u;
     84                 }
     85             }
     86         }
     87         return true;
     88     }
     89 }spfa;
     90 int n, desnum, st, ed;
     91 int main()
     92 {
     93     char u[4],v[4];
     94     int Case = 1;
     95     while (~scanf("%d", &n) && n != -1)
     96     {
     97         spfa.Init();
     98         for (int i = 1; i <= n; i++)
     99         {
    100             scanf("%s%s", u, v);
    101             int ui, vi;
    102             if (isupper(u[0])) ui = u[0] - 'A' + 26;
    103             else ui = u[0] - 'a';
    104             if (isupper(v[0])) vi = v[0] - 'A' + 26;
    105             else vi = v[0] - 'a';
    106             spfa.addedge(ui, vi);
    107         }
    108         scanf("%d%s%s", &desnum, u, v);
    109         
    110         if (isupper(u[0])) st = u[0] - 'A' + 26;
    111         else st = u[0] - 'a';
    112         if (isupper(v[0])) ed = v[0] - 'A' + 26;
    113         else ed = v[0] - 'a';
    114 
    115         spfa.set(60, st, ed);
    116         spfa.cal_spfa(desnum);
    117         printf("Case %d:
    ", Case++);
    118         printf("%lld
    ", spfa.dis[st]);
    119         int tmp =st;
    120         while (true)
    121         {
    122             if (tmp == ed)
    123             {
    124                 printf("%c
    ", v[0]);
    125                 break;
    126             }
    127             char p;
    128             if (tmp < 26) p = 'a' + tmp;
    129             else p = 'A' + (tmp - 26);
    130             printf("%c-", p);
    131             tmp = spfa.pre[tmp];
    132         }
    133     }
    134     return 0;
    135 }
    View Code

    4、uva 11090 Going in Cycle!!

      题意:给出有环有向图,求所存在的环中边权平均值最小是多少?

      思路:二分答案,如果所有边都减去当前值,SPFA判断存在负环,则说明当前值太大,最小平均值肯定比它要小;如果不存在负环,则说明减的不够大,最小平均值一定比其大。

      1 #include<iostream>
      2 #include<algorithm>
      3 #include<queue>
      4 #include<cstring>
      5 #include<vector>
      6 using namespace std;
      7 const int maxn = 60;
      8 const int INF = 0x3f3f3f3f;
      9 struct edge
     10 {
     11     int from, to, next;
     12     double cost;
     13     edge(int ff=0,int tt=0,int cc=0,int nn=0):from(ff),to(tt),cost(cc),next(nn){ }
     14 };
     15 vector<edge>Edge;
     16 int Head[maxn], totedge;
     17 int N, M;
     18 
     19 
     20 struct SPFA
     21 {
     22     int n, st;
     23     bool vis[maxn];
     24     double dis[maxn];
     25     int cnt[maxn];
     26     bool visn[maxn];
     27     void Init()
     28     {
     29         memset(Head, -1, sizeof(Head));
     30         totedge = 0;
     31         Edge.clear();
     32     }
     33     void set(int nodes, int source)
     34     {
     35         n = nodes, st = source;
     36     }
     37     void addedge(int from, int to, double cap)
     38     {
     39         Edge.push_back(edge(from, to, cap, Head[from]));
     40         Head[from] = totedge++;
     41     }
     42     bool cal_spfa()
     43     {
     44         memset(vis, 0, sizeof(vis));
     45         memset(dis, INF, sizeof(dis));
     46         memset(cnt, 0, sizeof(cnt));
     47 
     48         queue<int>q;
     49         q.push(st);
     50         vis[st] = true;
     51         cnt[st]++;
     52         dis[st] = 0;
     53         while (!q.empty())
     54         {
     55             int u = q.front();
     56             q.pop();
     57             visn[u] = true;
     58             vis[u] = false;
     59             for (int i = Head[u]; i != -1; i = Edge[i].next)
     60             {
     61                 int v = Edge[i].to;
     62                 if (dis[v] > dis[u] + Edge[i].cost)
     63                 {
     64                     dis[v] = dis[u] + Edge[i].cost;
     65                     if (!vis[v])
     66                     {
     67                         vis[v] = true;
     68                         q.push(v);
     69                         cnt[v]++;
     70                         if (cnt[v] > n) return false;
     71                     }
     72                 }
     73             }
     74         }
     75         return true;
     76     }
     77     bool binsolve(double mid)
     78     {
     79         for (int i = 0; i < totedge; i++) Edge[i].cost -= mid;
     80         memset(visn, 0, sizeof(visn));
     81         bool isok = true;
     82         for (int i = 1; i <= N; i++)
     83         {
     84             if (!visn[i])
     85             {
     86                 set(N, i);
     87                 isok = cal_spfa();
     88                 if (!isok) break;
     89             }
     90         }
     91         for (int i = 0; i < totedge; i++) Edge[i].cost += mid;
     92         return isok;
     93     }
     94 }spfa;
     95 
     96 int main()
     97 {
     98     int t;
     99     scanf("%d", &t);
    100     int Case = 1;
    101     while (t--)
    102     {
    103         double L=INF, R=0;
    104         scanf("%d%d", &N, &M);
    105         spfa.Init();
    106         for (int i = 1; i <= M; i++)
    107         {
    108             int from, to;
    109             double cost;
    110             scanf("%d%d%lf", &from, &to, &cost);
    111             spfa.addedge(from, to, cost);
    112             L = min(L, cost);
    113             R = max(R, cost);
    114         }
    115         if (spfa.binsolve(R+1000))
    116         {
    117             printf("Case #%d: No cycle found.
    ", Case++);
    118             continue;
    119         }
    120         while (R - L > 1e-6)
    121         {
    122             double mid = (R + L) / 2;
    123             if (!spfa.binsolve(mid)) R = mid;
    124             else L = mid;
    125         }
    126         printf("Case #%d: %.2lf
    ", Case++, L);
    127     }
    128     return 0;
    129 }
    View Code

    5、uva 11478 Halum

      题意:给出有向图,每一次可以把连向u的所有的边的边权减去di,把从u出发连向其他点的边的边权加上di.问经过若干次操作后,能否使图中所有边的边权都大于0,如果可以给出其最小值。

      思路:对于某一条有向边u--->v,设其边权为w,作用在该边上的最终结果为w+sum(u)-sum(v)>=ans.即sum(v)-sum(u)<=w-ans.即转换为差分约束问题。于是我们二分答案,让所有的边减去ans,然后判断是否存在负环,没有的话说明ans还可以增大,否则只能减小。注意这里的边权和di都是整数。

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<queue>
     4 #include<vector>
     5 #include<cstring>
     6 using namespace std;
     7 const int maxn = 510;
     8 const int INF = 0x3f3f3f3f;
     9 struct edge
    10 {
    11     int from, to, cost, next;
    12     edge(int ff=0,int tt=0,int cc=0,int nn=0):from(ff),to(tt),cost(cc),next(nn){ }
    13 };
    14 vector<edge>Edge;
    15 int Head[maxn], totedge;
    16 struct SPFA
    17 {
    18     int n, st, ed;
    19     int cnt[maxn];
    20     bool vis[maxn];
    21     int dis[maxn];
    22 
    23     void Init()
    24     {
    25         memset(Head, -1, sizeof(Head));
    26         totedge = 0;
    27         Edge.clear();
    28     }
    29     void addedge(int from, int to, int cost)
    30     {
    31         Edge.push_back(edge(from, to, cost, Head[from]));
    32         Head[from] = totedge++;
    33     }
    34     bool cal_spfa(int mid)
    35     {
    36         memset(cnt, 0, sizeof(cnt));
    37         queue<int>q;
    38         for (int i = 1; i <= n; i++) q.push(i), dis[i] = 0, vis[i] = true,cnt[i]=1;
    39         while (!q.empty())
    40         {
    41             int u = q.front();
    42             q.pop();
    43             vis[u] = false;
    44             for (int i = Head[u]; i != -1; i = Edge[i].next)
    45             {
    46                 int v = Edge[i].to;
    47                 if (dis[v] > dis[u] + Edge[i].cost - mid)
    48                 {
    49                     dis[v] = dis[u] + Edge[i].cost - mid;
    50                     if (!vis[v])
    51                     {
    52                         vis[v] = true;
    53                         q.push(v);
    54                         cnt[v]++;
    55                         if (cnt[v] >= n) return false;
    56                     }
    57                 }
    58             }
    59         }
    60         return true;
    61     }
    62 }spfa;
    63 int main()
    64 {
    65     int N,E;
    66     while (~scanf("%d%d", &N, &E))
    67     {
    68         spfa.Init();
    69         int l=1, r = -1;
    70         for (int i = 1; i <= E; i++)
    71         {
    72             int from, to, cost;
    73             scanf("%d%d%d", &from, &to, &cost);
    74             spfa.addedge(from, to, cost);
    75             r = max(r, cost);
    76         }
    77         spfa.n = N;
    78         if (spfa.cal_spfa(r))
    79         {
    80             printf("Infinite
    ");
    81         }
    82         else if (!spfa.cal_spfa(1))
    83         {
    84             printf("No Solution
    ");
    85         }
    86         else
    87         {
    88             while (l <= r)
    89             {
    90                 int mid = (l + r) / 2;
    91                 if (spfa.cal_spfa(mid)) l = mid+1;
    92                 else r = mid - 1;
    93             }
    94             printf("%d
    ", r);
    95         }
    96     }
    97     return 0;
    98 }
    View Code

     6、uvalive 3661 Animal Run

      题意:有n*m的方格,有横、竖、主对角线边。一群动物想要从左上角到达右下角。为了防止逃跑,每条道路都需要若干人员堵住。现在需要求最少的人数,使得没有一只动物能够逃离。

      思路:最简单的思路:求原图的最小割。但是会超时。因为原图为S-T平面图,转换为其对偶图,求由原图的面所构成的S*到T*的最短路即原图S到T的最小割。用SPFA的话,需要用优先队列优化。

      1 #include<iostream>
      2 #include<cstring>
      3 #include<queue>
      4 #include<cstdio>
      5 using namespace std;
      6 const int maxe = 1000 * 1000 * 3 * 2 + 100;
      7 const int maxn = 1000 * 1000*2 + 100;
      8 const int INF = 0x3f3f3f3f;
      9 struct edge
     10 {
     11     int from, to, cost, next;
     12     edge(int ff=0,int tt=0,int cc=0,int nn=0):from(ff),to(tt),cost(cc),next(nn){ }
     13 }Edge[maxe];
     14 int Head[maxn],totedge;
     15 
     16 struct node
     17 {
     18     int id, dist;
     19     node(int ii=0,int dd=0):id(ii),dist(dd){ }
     20     friend bool operator<(const node&a, const node&b)
     21     {
     22         return a.dist > b.dist;
     23     }
     24 };
     25 struct SPFA
     26 {
     27     int st, ed;
     28     int dis[maxn];
     29     bool vis[maxn];
     30     void Init()
     31     {
     32         memset(Head, -1, sizeof(Head));
     33         totedge = 0;
     34     }
     35     void Set(int source, int dest)
     36     {
     37         st = source, ed = dest;
     38     }
     39     void addedge(int from, int to, int cost)
     40     {
     41         Edge[totedge] = edge(from, to, cost, Head[from]);
     42         Head[from] = totedge++;
     43         Edge[totedge] = edge(to, from, cost, Head[to]);
     44         Head[to] = totedge++;
     45     }
     46     void Cal_spfa()
     47     {
     48         memset(dis, INF, sizeof(dis));
     49         memset(vis, 0, sizeof(vis));
     50         dis[st] = 0;
     51         priority_queue<node>q;
     52         q.push(node(st,0));
     53         while (!q.empty())
     54         {
     55             node cur = q.top();
     56             q.pop();
     57             int u = cur.id;
     58             if (vis[u]) continue;
     59             vis[u] = true;
     60             for (int i = Head[u]; i != -1; i = Edge[i].next)
     61             {
     62                 int v = Edge[i].to;
     63                 if (dis[v] > dis[u] + Edge[i].cost)
     64                 {
     65                     dis[v] = dis[u] + Edge[i].cost;
     66                     q.push(node(v, dis[v]));
     67                 }
     68             }
     69         }
     70     }
     71 }spfa;
     72 int main()
     73 {
     74     int n, m;
     75     int Case = 1;
     76     while (~scanf("%d%d", &n, &m) && (n + m))
     77     {
     78         spfa.Init();
     79         int nums = (n-1)*(m-1) * 2;
     80         int source = nums + 1, dest = nums + 2;
     81         //
     82         for (int i = 1; i <= n; i++)
     83         {
     84             for (int j = 1; j <= m - 1; j++)
     85             {
     86                 int cap;
     87                 scanf("%d", &cap);
     88                 if (i == 1)
     89                 {
     90                     spfa.addedge(j * 2, dest, cap);
     91                 }
     92                 else if (i == n) spfa.addedge(source, (i - 2) *(m-1)* 2 + j * 2-1, cap);
     93                 else
     94                 {
     95                     spfa.addedge((i - 2)*(m - 1) * 2 + j * 2 - 1, (i - 1)*(m - 1) * 2 + j * 2, cap);
     96                 }
     97             }
     98         }
     99         //
    100         for (int i = 1; i <= n - 1; i++)
    101         {
    102             for (int j = 1; j <= m; j++)
    103             {
    104                 int cap;
    105                 scanf("%d", &cap);
    106                 if (j == 1)
    107                 {
    108                     spfa.addedge(source, (i - 1)*(m - 1)*2 + 1, cap);
    109                 }
    110                 else if (j == m)
    111                 {
    112                     spfa.addedge(i*(m-1)*2, dest, cap);
    113                 }
    114                 else
    115                 {
    116                     spfa.addedge((i - 1)*(m - 1) * 2 + (j - 1) * 2, (i - 1)*(m - 1) * 2 + (j - 1) * 2 + 1, cap);
    117                 }
    118             }
    119         }
    120         //对角线
    121         for (int i = 1; i <= n - 1; i++)
    122         {
    123             for (int j = 1; j <= m - 1; j++)
    124             {
    125                 int cap;
    126                 scanf("%d", &cap);
    127                 spfa.addedge((i - 1)*(m - 1) * 2 + j * 2 - 1,(i - 1)*(m - 1) * 2 + j * 2, cap);
    128             }
    129         }
    130         spfa.Set(source, dest);
    131         spfa.Cal_spfa();
    132         printf("Case %d: Minimum = %d
    ", Case++, spfa.dis[dest]);
    133     }
    134     return 0;
    135 }
    View Code

     7、uva 10603 Fill

      题意:有三个水壶a,b,c,其中a和b是空的,c是满的。每次可以把水从一个壶倒到另一个壶,直到前一个已经倒空或者后一个壶已经倒满。问最少的累计倒水的体积,使得其中某一个壶的水的体积为d?如果达不到d,则输出离d最近的那个目标体积的对应最少的累计倒水的体积。

      思路:通过BFS搜索,记录已经访问过的状态,每次更新达到壶中水的体积最少的累计次数。

     1 #include<iostream>
     2 #include<queue>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<cstdio>
     6 using namespace std;
     7 int c[3], d;
     8 const int maxv = 210;
     9 int dist[maxv];//得到容量为i最少的倒水体积
    10 bool vis[maxv][maxv];//表示a、b、c状态为i、j、d-i-j是否访问过
    11 struct node
    12 {
    13     int dis;//从开始到当前已倒过的水的体积
    14     int v[3];
    15     node(int dd=0,int vva=0,int vvb=0,int vvc=0):dis(dd)
    16     {
    17         v[0] = vva, v[1] = vvb, v[2] = vvc;
    18     }
    19     friend bool operator<(const node&a, const node&b)
    20     {
    21         return a.dis > b.dis;
    22     }
    23 };
    24 void BFS()
    25 {
    26     memset(dist, -1, sizeof(dist));
    27     memset(vis, 0, sizeof(vis));
    28     priority_queue<node>q;
    29     q.push(node(0, 0, 0, c[2]));
    30     vis[0][0] = true;
    31     while (!q.empty())
    32     {
    33         node cur = q.top();
    34         q.pop();
    35         for (int i = 0; i < 3; i++)
    36         {
    37             if (dist[cur.v[i]] == -1 || dist[cur.v[i]] > cur.dis) dist[cur.v[i]] = cur.dis;
    38         }
    39         for (int i = 0; i < 3; i++)
    40         {
    41             for (int j = 0; j < 3; j++)
    42             {
    43                 if (i == j || cur.v[i] == 0 || cur.v[j] == c[j]) continue;
    44                 int add = min(cur.v[i], c[j] - cur.v[j]);
    45                 node tmp = cur;
    46                 tmp.v[i] -= add;
    47                 tmp.v[j] += add;
    48                 tmp.dis += add;
    49                 if (!vis[tmp.v[0]][tmp.v[1]])//由于肯定会越倒,dis肯定越大,所以到后面如果出现重复的,则不再添加
    50                 {
    51                     vis[tmp.v[0]][tmp.v[1]] = 1;
    52                     q.push(tmp);
    53                 }
    54             }
    55         }
    56     }
    57 }
    58 int main()
    59 {
    60     int t;
    61     scanf("%d", &t);
    62     while (t--)
    63     {
    64         for (int i = 0; i <= 2; i++) scanf("%d", &c[i]);
    65         scanf("%d", &d);
    66         BFS();
    67         while (d >= 0)
    68         {
    69             if (dist[d] >= 0)
    70             {
    71                 printf("%d %d
    ", dist[d], d);
    72                 break;
    73             }
    74             d--;
    75         }
    76     }
    77     return 0;
    78 }
    View Code

     8、uva 10269 Adventure of Super Mario

      题意:给出无向图,求起点到终点的最小花费。每条路,如果走路,花费时间等于路的长度;如果坐magic boot,可以直达,时间为0.一次坐magic boot,可以经过多条道路,但是所有经过道路总长不超过L,并且途中不能穿过城堡。magic boot最多只能使用K次。

      思路:先求出两两可直达的最短距离(即途中不经过城堡)。然后spfa判断dis[i][k](到i处剩余k次时的最小花费)之间的转换,可通过优先队列优化。(原本以为dis一维可以,用队列记录到达的结点和飞行情况,但是解不出来……)

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 #include <cmath>
      5 #include <cstdlib>
      6 #include <queue>
      7 using namespace std;
      8 
      9 const int maxn = 155;
     10 const int INF = 0x3f3f3f3f;
     11 typedef long long ll;
     12 int A, B, M, L, K;
     13 int mp[maxn][maxn];
     14 
     15 void floyd()
     16 {
     17     for (int k = 1; k <= A; k++)
     18     {
     19         for (int i = 1; i <= A + B; i++)
     20         {
     21             for (int j = 1; j <= A + B; j++)
     22             {
     23                 if (mp[i][j] > mp[i][k] + mp[k][j])
     24                 {
     25                     mp[i][j] = mp[i][k] + mp[k][j];
     26                 }
     27             }
     28         }
     29     }
     30 }
     31 
     32 struct node
     33 {
     34     int u, k, cos;//当前结点、剩余次数、花费
     35     node(int uu = 0, int kk = 0, int cc = 0) :u(uu), k(kk), cos(cc)
     36     {}
     37     bool operator <(const node& a)const
     38     {
     39         return cos > a.cos;
     40     }
     41 };
     42 int dis[maxn][15];
     43 int spfa()
     44 {
     45     priority_queue<node> Q;
     46     for (int i = 0; i <= A + B; i++)
     47     {
     48         for (int j = 0; j <= 12; j++)
     49         {
     50             dis[i][j] = INF;
     51         }
     52     }
     53     Q.push(node(A + B, K, 0));
     54     dis[A + B][K] = 0;
     55     while (!Q.empty())
     56     {
     57         int u = Q.top().u;
     58         int k = Q.top().k;
     59         if (u == 1) return Q.top().cos;
     60         Q.pop();
     61         for (int i = 1; i <= A + B; i++)
     62         {
     63             if (i == u) continue;
     64             if (mp[u][i] == INF) continue;
     65             if (dis[i][k] > dis[u][k] + mp[u][i])
     66             {
     67                 dis[i][k] = dis[u][k] + mp[u][i];
     68                 Q.push(node(i, k, dis[i][k]));
     69             }
     70             if (mp[u][i] <= L && dis[i][k - 1] > dis[u][k] && k != 0)
     71             {//如果可以花费一次使用次数从u直接到i
     72                 dis[i][k - 1] = dis[u][k];
     73                 Q.push(node(i, k - 1, dis[i][k - 1]));
     74             }
     75         }
     76     }
     77 }
     78 
     79 int main()
     80 {
     81     int T;
     82     scanf("%d", &T);
     83     while (T--)
     84     {
     85         scanf("%d %d %d %d %d", &A, &B, &M, &L, &K);
     86         memset(mp, INF, sizeof(mp));
     87         for (int i = 1; i <= A + B; i++)
     88         {
     89             mp[i][i] = 0;
     90         }
     91         int a, b, c;
     92         for (int i = 0; i < M; i++)
     93         {
     94             scanf("%d %d %d", &a, &b, &c);
     95             mp[a][b] = mp[b][a] = c;
     96         }
     97         floyd();
     98         printf("%d
    ", spfa());
     99     }
    100     return 0;
    101 }
    View Code

     

  • 相关阅读:
    BAT 批处理脚本教程
    javascript定时器
    使用命令行打开文件夹并显示
    用cmd加密文件夹
    烟波钓叟歌概述讲解
    奇门遁甲的起源
    八卦基本知识
    word2vec和word embedding有什么区别?
    Privoxy shadowscocks代理
    Elasticsearch源码分析—线程池(十一) ——就是从队列里处理请求
  • 原文地址:https://www.cnblogs.com/ivan-count/p/7847092.html
Copyright © 2011-2022 走看看