前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【 HDU 4936 】Rainbow Island (hash + 高斯消元)

【 HDU 4936 】Rainbow Island (hash + 高斯消元)

作者头像
饶文津
发布2020-06-02 12:31:33
3600
发布2020-06-02 12:31:33
举报
文章被收录于专栏:饶文津的专栏

BUPT2017 wintertraining(15) #5B HDU - 4936 2014 Multi-University Training Contest 7 F

题意

直接看官方的题意和题解吧(来自:2014年多校的题解博客)。

Rainbow Island
Rainbow Island

题解

官方的不够细,我再梳理一下吧。

预处理:

高斯消元

代码

代码语言:javascript
复制
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#define N 22
#define M 1000007
using namespace std;
int cas,t,n,cnt,a[N];
int f[M+1],mg[700][N][N];
//f[code]:code对应的状态
//mg[s][x][y]:状态s的第x和第y个合并后的状态
double p[N],dp[700][N],g[N][N];
//dp[st][i],当前状态st,人在第i个岛上,到达目标状态的期望值
vector<int>s[N];

struct sta{
	int a[N],tot;
}st[700];

int code(sta t){
	int b=t.tot;
	for(int i=1;i<=t.tot;i++)
		b=(b*233%M+t.a[i])%M; //hash
	return b;
}
void dfs(int d,int k,int sum){
	if(sum==n){
		sta &t=st[++cnt];
		t.tot=d-1;
		for(int i=1;i<d;i++)
			t.a[i]=a[i];
		f[code(t)]=cnt;
		return;
	}
	for(int i=k;i<=n-sum;i++)
		dfs(d+1,a[d]=i,sum+i);
}
int merge(sta t,int x,int y){
	t.a[x]+=t.a[y];
	swap(t.a[y],t.a[t.tot--]);
	sort(t.a+1,t.a+t.tot+1);
	return f[code(t)];
}

void pre(){
//求出所有可能的状态并hash处理,求出合并两个联通块后对应的状态
	cnt=0;
	dfs(1,1,0);
	for(int i=1;i<=cnt;i++)
		for(int x=1;x<st[i].tot;x++)
		for(int y=x+1;y<=st[i].tot;y++)
			mg[i][x][y]=merge(st[i],x,y);
}
void gauss(double x[]){
	for(int i=1;i<=n;i++){
		int r=i;
		while(!g[r][i]&&r<=n)r++;
		if(r>n)return;
		swap(g[r],g[i]);
		for(int j=i+1;j<=n;j++){
			double t=g[j][i]/g[r][i];
			for(int k=1;k<=n+1;k++)
				g[j][k]-=t*g[r][k];
		}
	}
	for(int i=n;i;i--)if(g[i][i]){//注意判断
		x[i]=g[i][n+1]/g[i][i];
		for(int j=1;j<i;j++)
			g[j][n+1]-=g[j][i]*x[i];
	}
}
void work(){
	memset(dp,0,sizeof dp);
	for(int i=cnt-1;i>=1;i--){
		memset(g,0,sizeof g);
		for(int j=1;j<=n;j++){
			double b=1;
			for(int x=1;x<st[i].tot;x++)
			for(int y=x+1;y<=st[i].tot;y++){
				int k=mg[i][x][y];
				double ps=p[j]*st[i].a[x]*st[i].a[y]/(n*(n-1)/2)/s[j].size();
				for(int u=0;u<s[j].size();u++){
					int v=s[j][u];
					b+=dp[k][v]*ps;
				}
			}
			g[j][j]=1;
			g[j][n+1]=b;
			double ps=0;
			for(int x=1;x<=st[i].tot;x++)
				ps+=st[i].a[x]*(st[i].a[x]-1);//连接同一联通块的岛的彩虹个数*2
			ps/=n*(n-1);//除以 2*总的彩虹个数(n*(n-1)/2)
			ps=(ps*p[j]+1-p[j])/s[j].size();
			for(int u=0;u<s[j].size();u++){
				int v=s[j][u];
				g[j][v]-=ps;
			}
		}
		gauss(dp[i]);
	}
}
int main() {
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
			scanf("%lf",&p[i]),s[i].clear();
		for(int i=1,t,v;i<=n;i++){
			scanf("%d",&t);
			while(t--){
				scanf("%d",&v);
				s[i].push_back(v);
			}
		}
		pre();
		work();
		printf("Case #%d: %f\n",++cas,dp[1][1]);
	}	
	return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017-03-01 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 题意
  • 题解
    • 预处理:
      • 高斯消元
      • 代码
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档