uva1390 Interconnect(状态数组dp)
2015-06-04 00:14
603 查看
关键词:hash用法,hash与状态数组dp
题意:已知一个无向图,每次随机选出两点生成新边,求该图成为连通图的期望添边数。
解法:每个连通状态构成一个数组。如何进行数组的状态表示和转移——hash。将每个状态数组经过hash后成为一个hash范围内的数字。
好处:
1.缩小比较范围。只需要在hsah值相同时才需要判断数组状态是否相同。
2.可以进行状态记录,方便记忆化搜索,提高时间效率。
题意:已知一个无向图,每次随机选出两点生成新边,求该图成为连通图的期望添边数。
解法:每个连通状态构成一个数组。如何进行数组的状态表示和转移——hash。将每个状态数组经过hash后成为一个hash范围内的数字。
好处:
1.缩小比较范围。只需要在hsah值相同时才需要判断数组状态是否相同。
2.可以进行状态记录,方便记忆化搜索,提高时间效率。
#include <stdio.h> #include <string.h> #include <set> #include <map> #include <algorithm> #include<vector> #include<iostream> #include<queue> #define ll long long #define INF 0x3f3f3f3f using namespace std ; const int maxm = 1000+10; const int maxn =30+5; int cnt[maxn]; int n,m; bool vis[maxn][maxn],flag[maxn]; int num,tmp; struct Node{ int a[maxn]; double res; bool operator==(const Node &rhs)const{ for(int i=1;i<=n;i++) if(rhs.a[i]!=a[i]) return 0; return 1; } }A; const int maxhash = 1000007; int head[maxhash<<1],Next[maxhash<<2]; vector<Node> st; bool ok; int Hash(Node& A){ int hsum=0; for(int i=1;i<=n;i++){ hsum=(hsum*n+A.a[i])%maxhash; } return hsum; } int Vis(Node& A){//返回A在st中的位置 int u=Hash(A); for(int i=head[u];i!=-1;i=Next[i]) if(st[i]==A) { ok=1; return i; } st.push_back(A); int s=st.size()-1; Next[s]=head[u]; head[u]=s; return s; } double dp(Node& A){ ok=0; int id=Vis(A); if(ok) return st[id].res; if(A.a ==1) return st[id].res=0.0; double tmp=0.0,tmp2=0.0; for(int i=2;i<=n;i++){ if(A.a[i]) tmp=tmp+(double)((double)(A.a[i]*i*(i-1))/2.0); } tmp=(((1.0*n*(n-1))/2.0)-tmp)/((1.0*n*(n-1))/2.0); for(int i=1;i<=n;i++) if(A.a[i]){ for(int j=i;j<=n;j++) if(A.a[j]){ if(i==j&&A.a[i]<2) continue; double k; if(i==j) k=1.0*A.a[i]*(A.a[i]-1)/2.0; else k=A.a[i]*A.a[j]*1.0; A.a[i]--,A.a[j]--,A.a[i+j]++; tmp2=tmp2+(double)(k*i*j)/(double)(n*(n-1)*1.0/2.0)*dp(A); A.a[i]++,A.a[j]++,A.a[i+j]--; } } return st[id].res=(tmp2+1.0)/tmp; } void dfs(int u){ flag[u]=1,tmp++; for(int i=1;i<=n;i++){ if(vis[u][i]){ if(!flag[i]) dfs(i); } } } int main(){ while(scanf("%d%d",&n,&m)!=EOF){ memset(cnt,0,sizeof(cnt)); memset(A.a,0,sizeof(A.a)); memset(head,-1,sizeof(head)); memset(flag,0,sizeof(flag)); memset(vis,0,sizeof(vis)); st.clear(); for(int i=1;i<=m;i++){ int u,v; scanf("%d%d",&u,&v); vis[u][v]=vis[v][u]=1; } tmp; num=0; for(int i=1;i<=n;i++){ if(!flag[i]) { tmp=0; dfs(i); cnt[num++]=tmp; } } for(int i=0;i<num;i++){ if(cnt[i]) A.a[cnt[i]]++; } printf("%.10lf\n",dp(A)); } return 0; }
相关文章推荐
- qemu-kvm编译错误
- 弱网环境测试与重复提交问题总结
- 无限互联学习连载三 多线程单例
- 数据结构之链式队列的所有操作
- 一步消除导入Android项目所产生的错误
- Android-->动态加载Activity (不使用Intent,启动Activity)
- hdu 1133很无语的题
- Live Archive 3177 3177 - Beijing Guards 【枚举】
- j2ee爬坑行之二 servlet
- 感谢!
- 面试题:两个整型数,不准用if 、switch 、?:等判断语句求出两者大值,不能使用api
- viewpager翻页效果加标签点滚动效果
- plist
- 不改HOST,另类打开谷歌搜索的方法
- 关于小兵日历无法删除的解决办法
- 4.19
- 熟悉Windows XP系统
- Android的Style的使用
- Android的Style的使用
- int --string