Wifi Setup

来源:互联网 发布:使命召唤5知乎 编辑:程序博客网 时间:2024/05/17 22:21

题目链接

  • 题目大意:
    对于长度为2 * R的区间,建立一个基站的费用是A + B * R(A、B值给定),现在要使得所有点都被覆盖,求最小花费
  • 分析:
    先考虑分治法。对于一个区间[a, b],如果这个区间只有一个基站,那么直接求;如果至少有两个基站,那么中间一定有断开的点(即基站没有覆盖的线段),那么就可以分成两个区间来算。可是如此一来,可能会有很多重复的计算。假如一个区间有多个断点,那么在这些点都计算显然是没有必要的(这些问题之间有交集),所以会导致效率底下。
    既然解有最优子结构的特点,那么就可以考虑DP来解。在DP时,可以先计算[1, i],然后每次添加i + 1点。添加时,可以每次选择[1, i]中的一个点j,然后使[j, i]区间只建立一个基站,再加上[1, i - 1]的最优值即可。为什么使加进来的点和选定的点之间只有一个基站(即相连)呢?目的是为了不重复。我们可以这样想,考虑一下加进来的点和当前的区间,只有两种可能:要么和当前区间之间有连线要么没有。如果有连线那么就是上述的情况,如果没有连线那么肯定是单独一个点和剩下的最优解。
  • 详细过程:
    用ans2[i]表示[1, i]的最优值(此题的结果不能有后导零,所以现在都用结果的2倍,最后处理小数),那么ans2[i] = min(ans[j - 1] + f(j, i)),(1 <= j < i, f函数表示[j, i]区间只有一个基站的花费)
  • 总结:
    DP和分治法相比,分治法是将当前问题分解成两个最优子问题,而DP是一个子问题的不断增长最终得到解。
    分治法解决的一个关键是当子问题规模比较小时要能够直接求解,对于这个题,只有当区间长度为1时才能知道答案,而且分治的复杂度为O(n),所以不能解题
    DP一般思路是给定一个最优解,在此基础上增加范围然后也能求得最优解,一直下去直到求的结果
const int MAXN = 2100;int ans2[MAXN];int ipt[MAXN];int len, A, B;int main(){//    freopen("in.txt", "r", stdin);    while (cin >> len >> A >> B)    {        FE(i, 1, len)            cin >> ipt[i];        sort(ipt + 1, ipt + len + 1);        FE(i, 1, len)        {            int ans = INF;            FE(j, 1, i)            {                ans = min(ans, 2 * A + B * (ipt[i] - ipt[j]) + ans2[j - 1]);            }            ans2[i] = ans;        }        int ans = ans2[len];        cout << ans / 2;        if (ans % 2 != 0)            cout << ".5";        cout << endl;    }    return 0;}

观察上述式子:ans2[i] = min(ans[j - 1] + f(j, i)),只有f(j, i)与i有关,那么就有可能采用单调队列优化(关键看f函数的形式)

这个题的f(j, i) = 2 * A + B * (ipt[i] - ipt[j])那么是可以采用单调队列优化的

const int MAXN = 2100;int ans2[MAXN];int ipt[MAXN];int len, A, B;int q_index[MAXN], l, r;int calc(int ind){    return -B * ipt[ind] + ans2[ind - 1];}void Insert(int ind){    while (r >= l && calc(q_index[r]) > calc(ind))        r--;    q_index[++r] = ind;}int main(){//    freopen("in.txt", "r", stdin);    while (cin >> len >> A >> B)    {        l = 1;        r = 0;        FE(i, 1, len)            cin >> ipt[i];        sort(ipt + 1, ipt + len + 1);        FE(i, 1, len)        {            Insert(i);            ans2[i] = 2 * A + B * ipt[i] + calc(q_index[l]);        }        int ans = ans2[len];        cout << ans / 2;        if (ans % 2 != 0)            cout << ".5";        cout << endl;    }    return 0;}


7 0
原创粉丝点击