zoukankan      html  css  js  c++  java
  • poj 1639 Picnic Planning 度限制mst

    https://vjudge.net/problem/POJ-1639

    题意:

    有一群人,他们要去某一个地方,每个车可以装无数个人,给出了n条路,包含的信息有路连接的地方,以及路的长度,路是双向的,但是终点只有一个,并且终点能停的车的数量是有限制的,问最少走的路是多少。

    思路:

    因为终点的停车的数量是有限制的,所以终点的度是有限制的,又因为这题可以用最小生成树解决,所以就是度限制最小生成树。

    度限制最小生成树求解思想并不复杂,首先我们把有度限制的点给忽略,然后给每一个连通分量求最小生成树,最后把每一个连通分量中与有度限制的点的距离最小的点与度限制点连接,假设有m个连通分量。

    那么我们现在求出了m限制的最小生成树,假如限制数k < m,那么就无解。

    当k >= m时,我们可以在m度限制mst的基础上,求m + 1,m + 2。。。k度限制最小生成树,求法也不是很难懂,但是程序就很难写了Orz。

    如何求呢?枚举每一条未在生成树中与(现在我们把度限制点叫做R点)R点相连的边,然后把边加入生成树,必然会形成环,然后把环中与R点不相连的权值最大的边去掉,枚举之后的最小值就是m+1度限制最小生成树的值。然后依次求到k限制mst,求其中的最小值。

    但是,依次枚举的话时间复杂度非常高,所以我们要优化。这时就用到了动态规划的思想。将与R点到其它点的边权值最大求出,之后加边的时候,直接替换就可以了。

    转移方程 dp[v] = max(dp[father(v)],w(v , father(v)));

    看不懂就多看几遍Orrrrrrrrrrrrrrrrrrrrrrrrz。

    代码:

      1 #include <stdio.h>
      2 #include <algorithm>
      3 #include <iostream>
      4 #include <string.h>
      5 #include <map>
      6 #include <string>
      7 using namespace std;
      8 
      9 const int inf = 0x3f3f3f3f;
     10 
     11 struct edge
     12 {
     13     int x,y;
     14     int v;
     15 } a[5055],dp[5055];
     16 
     17 map<string,int> mmp;
     18 bool flag[105][105];
     19 int par[105];
     20 int g[105][105];
     21 
     22 int ans;
     23 int num;
     24 int du,lim;
     25 
     26 int fin(int x)
     27 {
     28     if (x == par[x]) return x;
     29     else return par[x] = fin(par[x]);
     30 }
     31 
     32 void unit(int x,int y)
     33 {
     34     x = fin(x);
     35     y = fin(y);
     36 
     37     if (x == y) return;
     38 
     39     par[x] = y;
     40 }
     41 
     42 void dfs(int cur,int pre)
     43 {
     44     for (int i = 2;i <= num;i++)
     45     {
     46         if (i != pre && flag[cur][i])
     47         {
     48             if (dp[i].v == -1)
     49             {
     50                 if (dp[cur].v > g[cur][i])
     51                 {
     52                     dp[i] = dp[cur];
     53                 }
     54                 else
     55                 {
     56                     dp[i].x = cur;
     57                     dp[i].y = i;
     58                     dp[i].v = g[cur][i];
     59                 }
     60             }
     61 
     62             dfs(i,cur);
     63         }
     64     }
     65 }
     66 
     67 void solve(void)
     68 {
     69     for (int i = du + 1;i <= lim;i++)
     70     {
     71         memset(dp,-1,sizeof(dp));
     72 
     73         dp[1].v = -inf;
     74 
     75         for (int j = 2;j <= num;j++)
     76             if (flag[j][1]) dp[j].v = -inf;
     77 
     78         dfs(1,-1);
     79 
     80         int mi = inf,tmp;
     81 
     82         for (int j = 2;j <= num;j++)
     83         {
     84             if (g[1][j] != -1)
     85             {
     86                 if (mi > g[1][j] - dp[j].v)
     87                 {
     88                     mi = g[1][j] - dp[j].v;
     89                     tmp = j;
     90                 }
     91             }
     92         }
     93 
     94         if (mi >= 0) break;
     95 
     96         ans += mi;
     97 
     98         int x = dp[tmp].x,y = dp[tmp].y;
     99 
    100         flag[x][y] = flag[y][x] = 0;
    101 
    102         flag[1][tmp] = flag[tmp][1] = 1;
    103     }
    104 }
    105 
    106 int get_num(string aa)
    107 {
    108     if (mmp[aa]) return mmp[aa];
    109     else
    110     {
    111         mmp[aa] = ++num;
    112         return num;
    113     }
    114 }
    115 
    116 bool cmp(edge aa,edge bb)
    117 {
    118     return aa.v < bb.v;
    119 }
    120 
    121 int main()
    122 {
    123     num = 1;
    124 
    125     mmp["Park"] = 1;
    126 
    127     memset(g,-1,sizeof(g));
    128 
    129     int n;
    130 
    131     scanf("%d",&n);
    132 
    133     for (int i = 0;i < n;i++)
    134     {
    135         string aa,bb;
    136         int v;
    137 
    138         cin >> aa >> bb;
    139 
    140         scanf("%d",&v);
    141 
    142         int x = get_num(aa),y = get_num(bb);
    143 
    144         if (g[x][y] == -1) g[x][y] = g[y][x] = v;
    145         else g[x][y] = g[y][x] = min(v,g[x][y]);
    146 
    147         a[i].x = x;
    148         a[i].y = y;
    149         a[i].v = g[x][y];
    150     }
    151 
    152     for (int i = 0;i <= num;i++) par[i] = i;
    153 
    154     scanf("%d",&lim);
    155 
    156     sort(a,a+n,cmp);
    157 
    158     for (int i = 0;i < n;i++)
    159     {
    160         int x = a[i].x,y = a[i].y;
    161 
    162         if (x == 1 || y == 1) continue;
    163         if (fin(x) == fin(y)) continue;
    164 
    165         ans += a[i].v;
    166 
    167         unit(x,y);
    168 
    169         flag[x][y] = flag[y][x]  =1;
    170     }
    171 
    172     int minn[105],tmp[105];
    173 
    174     memset(minn,inf,sizeof(minn));
    175 
    176     for (int i = 2;i <= num;i++)
    177     {
    178         int rt = fin(i);
    179 
    180         if (g[1][i] != -1)
    181         {
    182             if (g[1][i] < minn[rt])
    183             {
    184                 minn[rt] = g[1][i];
    185                 tmp[rt] = i;
    186             }
    187         }
    188     }
    189 
    190     for (int i = 2;i <= num;i++)
    191     {
    192         if (minn[i] != inf)
    193         {
    194             du++;
    195             flag[1][tmp[i]] = flag[tmp[i]][1] = 1;
    196             ans += minn[i];
    197         }
    198     }
    199 
    200     solve();
    201 
    202     printf("Total miles driven: %d
    ",ans);
    203 
    204     return 0;
    205 }
  • 相关阅读:
    Postman几种常用方式
    PL/SQL 循环结构
    【oracle】解锁oracle用户,unlock
    四则运算题2
    有关Botton的用法(一)
    SQLiteOpenHelper的使用
    用Toast来增加调试效率的小技巧
    汇编语言-比较字符串
    正向代理和反向代理
    redis安装与配置
  • 原文地址:https://www.cnblogs.com/kickit/p/7415849.html
Copyright © 2011-2022 走看看