UVA1456 Cellular Network

链接

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4202

题解

这题条件有点多,但是我们给它一层层剥开就发现这个题其实没那么复杂
集合划分显然是不一定的,但是 n=100 n = 100 似乎不是状压 DP D P ,所以说我们不可能去枚举集合
但是不难发现,任何一种方案,都可以理解成把原序列进行一定的排序后,划分成恰好 m m 个区间,最小代价是多少
那么立刻就能想到一种做法:随机化顺序若干次,每次做这样的DP:f[i][j]表示前i个位置恰好划分成了 j j 个区间的最小代价
但是每次dp O(n3) O ( n 3 ) 的,不能进行太多次数的随机化,况且精度要求太高,这个方案舍弃
考虑:对于一种区间划分,我怎样对原序列排序能使得代价最小?
你想啊,前面的系数小,后面的系数大,当然是从大到小排个序了!
于是这题就做完了:
先从大到小排序,然后 DP D P

代码

//贪心+dp
#include <cstdio>
#include <cctype>
#include <algorithm>
#include <cstring>
#define maxn 110
#define cl(x,y) memset(x,y,sizeof(x))
#define inf 0x3f3f3f3f
using namespace std;
int f[maxn][maxn], N, u[maxn], W, U;
int read(int x=0)
{
    char c, f=1;
    for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-1;
    for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-48;
    return f*x;
}
bool cmp(int a, int b){return a>b;}
void init()
{
    int i;
    N=read(), W=read();
    for(i=1,U=0;i<=N;i++)u[i]=read(), U+=u[i];
    sort(u+1,u+N+1,cmp);
    for(i=1;i<=N;i++)u[i]+=u[i-1];
    cl(f,inf);
}
void dp()
{
    int i, j, k;
    f[0][0]=0;
    for(i=1;i<=N;i++)for(j=1;j<=W;j++)for(k=0;k<i;k++)f[i][j]=min(f[i][j],f[k][j-1]+i*(u[i]-u[k]));
    printf("%.4lf\n",(double)f[N][W]/U);
}
int main()
{
    int T=read();
    while(T--)init(), dp();
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值