uva live 4731 Cellular Network 线性dp

// uva live 4731
//
// 状态很好想:
// d(i,j)表示前i个网络分为j组所得到的数学期望的最小值
// 转移方程:
// d(i,j) = min(d(k,j-1)+cost);
// cost由题目给出的条件可知cost = (k+1...i)段的概率和 * i;
//
// 注意:
// 1)肯定概率大的网络分在前面,这样在后面的话,这个大的概率出现在
// 后面的机会就会小。因为每个概率都会至少要算一次,所以先算大的
// 可以尽量减少后面再算大的。
// 2 )初始化的时候只有d(0,0)才是0.0,其他都是inf,因为任意一个不是0的i
// 都不可能有d(i,0)这种状况出现;

// 感悟:
// 总的来说,并不算是很难,只要题目意思看懂了就还行,一直在纠结
// 这个公式是怎么证明的,最后本人实在太笨,只能按照题目给的公式
// 直接硬上喽,如果有人能解答我的疑惑,$2.56小子双手奉上,并致以
// 最为诚挚的感谢

#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <cfloat>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <functional>
#include <iostream>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <vector>
#define ceil(a,b) (((a)+(b)-1)/(b))
#define endl '\n'
#define gcd __gcd
#define highBit(x) (1ULL<<(63-__builtin_clzll(x)))
#define popCount __builtin_popcountll
typedef long long ll;
using namespace std;
const int MOD = 1000000007;
const long double PI = acos(-1.L);
int n,w;
const int maxn = 180;
double d[maxn][maxn];
bool vis[maxn][maxn];
int x[maxn];
double s[maxn];

bool cmp(int x,int y){
	return x>y;
}

double dp(int num,int wi){
	if (vis[num][wi])	return d[num][wi];
	vis[num][wi] = 1;

	if (wi==0 || num == 0)	return d[num][wi];
	for (int i=0;i<=num;i++)
		d[num][wi] = min(d[num][wi],dp(i,wi-1)+(s[num]-s[i]) * num);
	return d[num][wi];
}

void print(){
	for (int i=1;i<=n;i++){
		for (int j=1;j<=n;j++){
			cout << d[i][j] << " ";
		}
		cout << endl;
	}
}

void prin(){
	for (int i=1;i<=n;i++)
		cout << s[i] << " ";
	cout << endl;
}

void init(){
	scanf("%d%d",&n,&w);
	double sum = 0.0;
	for (int i=1;i<=n;i++){
		scanf("%d",&x[i]);
		sum +=x[i];
	}
	sort(x+1,x+n+1,cmp);
	s[0] = 0.0;
	for (int i=1;i<=n;i++){
		s[i] = s[i-1] + x[i]/sum;
	}
	//prin();
	memset(vis,0,sizeof(vis));
	for(int i=0;i<=n;i++)
		for (int j=0;j<=n;j++){
			d[i][j] = 999999999;
		}
	d[0][0]=0.0;
	printf("%.4lf\n",dp(n,w));
	//print();
	//puts("");
}

int main() {
	int t;
	//freopen("1.txt","r",stdin);
	scanf("%d",&t);
	while(t--){
		init();
	}
	return 0;
}

时间: 2024-12-19 05:34:44

uva live 4731 Cellular Network 线性dp的相关文章

UVA 1456 六 Cellular Network

Cellular Network Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Practice UVA 1456 A cellular network is a radio network made up of a number of cells each served by a base station located in the cell. The base sta

uva 11584 Partitioning by Palindromes 线性dp

// uva 11584 Partitioning by Palindromes 线性dp // // 题目意思是将一个字符串划分成尽量少的回文串 // // f[i]表示前i个字符能化成最少的回文串的数目 // // f[i] = min(f[i],f[j-1] + 1(j到i是回文串)) // // 这道题还是挺简单的,继续练 #include <algorithm> #include <bitset> #include <cassert> #include <

UVALive 4731 Cellular Network

分析: 状态是一些有序的集合,这些集合互不相交,并集为所有区域.显然枚举集合元素是哪些是无法承受的, 写出期望的计算式,会发现一个贪心,当每个集合的大小确定了以后,概率大的优先访问是最优的.容易证明,也符合直觉. 因此先对u从大到小排序.定义状态f[i][j]表示从j开始往后分i组的最小期望. 转移是枚举划分k,则有f[i][j] = min{f[i-1][k]+(k-j)*(u[n]-u[j-1])},k>j 边界f[1][j] = (n-j+1)*(u[n]-u[j-1]) #include

uva 11552 Fewest Flops 线性dp

// uva 11552 Fewest Flops // // 二维线性dp // // 首先,在该块必须是相同的来信.首先记录每块有很多种书 // 称为是counts[i]; // // 订购f[i][j]它代表前i字母j为结尾的最小分块数 // // 假设第i块的開始字母与第i-1块的结束字母同样 // f[i][j] = min(f[i][j],f[i-1][k] + counts[i] - 1); // // 否则 // // f[i][j] = min(f[i][j],f[i-1][k

UVa 457 - Linear Cellular Automata

题目:有40个培养皿,每个培养皿中有一个数字(0-9).最开始时20号中数字为1,其余为0. 每组输入有一个DNA programs(10个数字构成的序列),它决定每个培养皿下个时间的数字. 设培养皿i中的数字为F(i),则下次其中的数字为DNA(F(i-1)+F(i)+F(i+1)) {即,编号为F(i-1)+F(i)+F(i+1)的DNA programs中对应的数字}. 在给定DNA programs的情况下,输出所有培养皿中从第1-50天的数字. 分析:模拟,dp.读完题目,问题也基本解

uva live 4394 String painter 区间dp

// uva live 4394 String painter // // 这一题是训练指南上dp专题的习题,初看之下认为仅仅是稍微复杂了一点 // 就敲阿敲阿敲,两个半小时后,发现例子过了.然而自己给出的数据跪了 // 交了也wa了,才发现,自己的方法是有问题的,假设是将两个串同一时候考虑 // 的话,比方: dp[i][j] 表示从i到j,s串刷成目标b串所须要的最小的花费 // 然后依据区间的端点的字符特点,进行状态转移,然而可能是我太搓了, // 发现这种状态转移是不正确的.比方edc和

uva live 4394 String painter 间隔dp

// uva live 4394 String painter // // 问题是,在培训指导dp运动主题,乍一看,我以为只是一点点复杂 // A A磕磕磕,两个半小时后,.发现超过例子.然而,鉴于他们跪在数据 // 还要wa.才发现,自己的方法是有问题的,假设是将两个串同一时候考虑 // 的话.比方: dp[i][j] 表示从i到j,s串刷成目标b串所须要的最小的花费 // 然后依据区间的端点的字符特点,进行状态转移.然而可能是我太搓了. // 发现这种状态转移是不正确的,比方edc和cde.

UVa1456Cellular Network(概率DP)

Cellular Network Description A cellular network is a radio network made up of a number of cells each served by a base station located in the cell. The base station receives call signals from mobile users (mobiles) in the cell it serves, which then co

UVA - 825Walking on the Safe Side(dp)

题目: UVA - 825Walking on the Safe Side(dp) 题目大意:给出一个n * m的矩阵,起点是1 * 1,终点是n * m,这个矩阵上有些点是不可以经过的,要求从起点到终点距离最短,并且不能走那种不能走的点,一共有多少种方式. 解题思路:要求路径最短的话,每个点要不向右走,要不向下走.dp[i][j] = dp[i][j + 1] + dp[i + 1][j]:当这个点不能通过,dp[i][j] = 0:这个坑点在样例输入,不一定是规范的输入,可能两个数字之间很多