coin - dp - 贪心

题目大意:有n个人m种物品,给出p(i,j)表示第i个人喜欢物品j的概率。
现在你要选择n件物品,执行下述操作:从第一个人开始,若现在手上有这个人喜欢的物品,就ans++并移除这个物品。求一个方案使得ans期望最大。
题解:考虑给定一种方案如何算E(ans)。不男发现每种物品独立,因此统计一个g[i,j]表示有恰好j个人喜欢物品i的概率。
那么再用一个dp决策一下每个物品选多少即可。
注意到这个你每多选第i个物品1件,就相当于是加上g[i]的一个后缀和,那么每次的增量是递减的,因此可以贪心代替这个dp。
那么只需要有n个g[i,j]需要计算,维护G[i,j]表示第i个物品前j个人有恰好cur(cur表示贪心时第i个物品选了几个)个人选了i的概率即可。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;typedef long double db;namespace INPUT_SPACE{
	const int BS=(1<<24)+5;char Buffer[BS],*HD,*TL;char gc() { if(HD==TL) TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);return (HD==TL)?EOF:*HD++; }
	inline int inn() { int x,ch;while((ch=gc())<'0'||ch>'9');x=ch^'0';while((ch=gc())>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^'0');return x; }
}using INPUT_SPACE::inn;const int M=310,N=3010;db g[M][N],p[N][M],w[M],f[N];
inline int trans(db *g,int x,int n) { f[0]=0;rep(i,1,n) f[i]=p[i][x]*g[i-1]+(1-p[i][x])*f[i-1];rep(i,0,n) g[i]=f[i];return 0; }
int main()
{
	int n=inn(),m=inn();db ans=0;rep(i,1,n) rep(j,1,m) p[i][j]=inn()/1000.0;
	rep(i,1,m) g[i][0]=1;rep(i,1,m) rep(j,1,n) g[i][j]=g[i][j-1]*(1-p[j][i]);rep(i,1,m) w[i]=g[i][n];
	rep(i,1,n) { int x=1;rep(j,1,m) if(1-w[j]>1-w[x]) x=j;ans+=1-w[x],trans(g[x],x,n),w[x]+=g[x][n]; }
	return !printf("%.12lf\n",double(ans));
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/85091701