首页 > 代码库 > HDU 4921 Map DFS+状态压缩+乘法计数
HDU 4921 Map DFS+状态压缩+乘法计数
算最多十条链,能截取某前缀段,每种方案都可以算出一个权值,每种方案的概率都是总数分之一,问最后能构成的所有可能方案数。
对计数原理不太敏感,知道是DFS先把链求出来,但是想怎么统计方案的时候想了好久,其实因为只能取某个链的前缀,所以直接取链长加+1 然后相乘即可,当然因为会出现都是空的那种情况,要去掉,全部乘完之后,要-1
然后就是算权值了,权值等于当前加进来的点的总和 以及 等级相同的点的加成,并不是特别好算,这时候考虑每个状态下的点对全局的贡献,对,就是这个思想,用状态压缩来表示状态,然后这个状态占用的所有情况,又可以用乘法原理乘出来。然后对这个状态算出权值之后,乘以所有的占用情况即可
下标是从0开始的,注意
#include <iostream>#include <cstdio>#include <cstring>#include <vector>#include <algorithm>using namespace std;const int N = 10010;int u[N],v[N],ft[N],nt[N];int ind[N],deep[N],val[N],vis[N];int n,m,cnt;vector <int> ve[20];int dir[20],sz[1100],cur;void init(){ for (int i=0;i<=n;i++){ ft[i]=-1; ind[i]=0; vis[i]=0; } cnt=0; cur=0; for (int i=0;i<20;i++){ ve[i].clear(); } for (int i=0;i<1100;i++) sz[i]=0;}void add(int a,int b){ u[cnt]=a; v[cnt]=b; nt[cnt]=ft[a]; ft[a]=cnt++;}void dfs(int x){ if (vis[x]) return; vis[x]=1; for (int i=ft[x];i!=-1;i=nt[i]){ int vx=v[i]; if (vis[vx]) continue; ve[cur-1].push_back(vx); int len=ve[cur-1].size(); sz[len-1]++; dfs(vx); }}int main(){ int t,a,b; scanf("%d",&t); while (t--) { scanf("%d%d",&n,&m); init(); for (int i=0;i<n;i++){ scanf("%d",&val[i]); } while (m--) { scanf("%d%d",&a,&b); add(a,b); ind[b]++; } for (int i=0;i<n;i++){ if (vis[i]==0 && ind[i]==0){ dir[cur++]=i; ve[cur-1].push_back(i); dfs(i); sz[0]++; } } double tot=1; int maxn=0; for (int i=0;i<cur;i++){ int tmp=ve[i].size(); maxn=tmp>maxn?tmp:maxn; tot*=(double)(tmp+1); } tot-=1; double ans=0,sum=0; for (int i=0;i<maxn;i++){ // cout<<"Test "<<i<<endl; for (int j=1;j<(1<<cur);j++){ //cout<<"sta "<<j<<endl; sum=0; int tmp=0; double calc=1.0; for (int k=0;k<cur;k++){ int r=ve[k].size(); bool flag=((1<<k)&j); if (r<=i && flag){ sum=0; break; } if (i<r && flag){ sum+=(double)val[ve[k][i]]; tmp++; calc*=(double)(r-i); } else { calc*=(min(r,i)+1)*1.0; } } //cout<<"calc "<<calc<<endl; //cout<<"sum "<<sum<<endl; ans+=sum*calc; if (tmp>1) ans+=calc*(double)tmp/(double)sz[i]*sum; // cout<<"ans "<<ans<<endl; } } //cout<<"cur "<<cur<<endl; //cout<<ans<<" "<<tot<<endl; ans=ans/tot; printf("%.3lf\n",ans); } return 0;}
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。