1. 程式人生 > >NKOJ 打氣球【期望概率DP】

NKOJ 打氣球【期望概率DP】

很簡單啦,隨便寫寫然後記憶化實現一下就好了嘛:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define db double
#define sg string
#define ll long long
#define rep(i,x,y) for(ll i=(x);i<=(y);i++)
#define red(i,x,y) for(ll i=(x);i>=(y);i--)
using namespace std;

const ll N=2e3+5;

db f[N][N];
ll n,m,row[N],col[N];

inline ll read() {
	ll x=0;char ch=getchar();bool f=0;
	while(ch>'9'||ch<'0'){if(ch=='-')f=1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
	return f?-x:x;
}

void dfs(ll c,ll r ){
	if(f[c][r]!=-1) return ;
	
	if(!c&&!r) {
		f[c][r]=0.0;return ;
	}
	
	db ret=0.0;
	
	if(c) {
		dfs(c-1,r);
		ret+=(c*(n-r)*f[c-1][r]);
	}
	
	if(r) {
		dfs(c,r-1);
		ret+=(r*(n-c)*f[c][r-1]);
	}
	
	if(c&&r) {
		dfs(c-1,r-1);
		ret+=(c*r*f[c-1][r-1]);
	} 
	
	f[c][r]=1.0*(ret*1.0+n*n)/(1.0*(c+r)*n-1.0*c*r);
}

void File() {
	freopen("shoot.in","r",stdin);
	freopen("shoot.out","w",stdout);
}

int main() {
//	File();
	
	n=read(),m=read();
	
	rep(i,1,m) {
		ll x=read(),y=read();
		col[x]=1,row[y]=1;
	}
	
	ll c=0,r=0;
	
	rep(i,1,n) if(!col[i]) c++;
	
	rep(i,1,n) if(!row[i]) r++;
	
	rep(i,0,n) rep(j,0,n) f[i][j]=-1.0;
	
	dfs(c,r);
	
	printf("%.2lf",f[c][r]);

	return 0;
}