HDU_5045_Contest(状态压缩or最小费用最大流)
2014-09-28 17:37
323 查看
题型:动态规划OR网络流
题意:
n个队员做m道题,第i个小时做第i个题目。Pij表示第i个队员能做出第j个题目的概率。
在任意时刻,任意两个队员的编程时间之差不允许超过1个小时。
问能做出最多题目的期望。
分析:
题目,最多10个人做1000道题。
根据题目的限制条件,可以发现,可行方案的队员序列必须是每n个题目由n个不同的队员做,即队员的全排列。
例如3个人做5道题,12312就是合法的,122321是不合法的。
这样就可以讲问题缩小了,只需要对每n个题目进行求解最优解,如果暴力枚举全排列,复杂度10!。
方法一:
采用状态压缩,复杂度2^10,妥妥的A了。
对于m%n != 0,需要对剩余的部分处理一下。我懒得处理了,于是直接后面用0补全,变成整整的n/m+1部分,简单粗暴效果好。
方法二:
采用费用流。
由于每n个题由n个不同的人做,所以很容易看出是二分图最大权匹配问题。可以采用KM算法,我用的是费用流,源点到队员流量为1,费用为0;队员到各个题目的流量为1,费用为对应概率取负;题目到汇点流量为1,费用为0.
跑n/m+1边费用流。
注意数组开的稍微大一点,我数组开的感觉差不多,却多次TLE和RE,不知为毛。开大一点就A了。
代码:
状态压缩:
费用流:
题意:
n个队员做m道题,第i个小时做第i个题目。Pij表示第i个队员能做出第j个题目的概率。
在任意时刻,任意两个队员的编程时间之差不允许超过1个小时。
问能做出最多题目的期望。
分析:
题目,最多10个人做1000道题。
根据题目的限制条件,可以发现,可行方案的队员序列必须是每n个题目由n个不同的队员做,即队员的全排列。
例如3个人做5道题,12312就是合法的,122321是不合法的。
这样就可以讲问题缩小了,只需要对每n个题目进行求解最优解,如果暴力枚举全排列,复杂度10!。
方法一:
采用状态压缩,复杂度2^10,妥妥的A了。
对于m%n != 0,需要对剩余的部分处理一下。我懒得处理了,于是直接后面用0补全,变成整整的n/m+1部分,简单粗暴效果好。
方法二:
采用费用流。
由于每n个题由n个不同的人做,所以很容易看出是二分图最大权匹配问题。可以采用KM算法,我用的是费用流,源点到队员流量为1,费用为0;队员到各个题目的流量为1,费用为对应概率取负;题目到汇点流量为1,费用为0.
跑n/m+1边费用流。
注意数组开的稍微大一点,我数组开的感觉差不多,却多次TLE和RE,不知为毛。开大一点就A了。
代码:
状态压缩:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #define mt(a,b) memset(a,b,sizeof(a)) using namespace std; int n,m; double p[16][1024]; double dp[1<<10]; void init(){ for(int i=0;i<10;i++){ for(int j=0;j<1024;j++){ p[i][j] = 0.00; } } } int ONE(int x){ int num = 0; while(x){ if(x&1) num ++; x >>= 1; } return num; } int main(){ int _; int Cas = 0; scanf("%d",&_); while(_--){ scanf("%d%d",&n,&m); init(); for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ scanf("%lf",&p[i][j]); } } printf("Case #%d: ",++Cas); int part = m/n; if(m%n!=0){ part++; } // printf("part = %d\n",part); double ans = 0.0; int all = (1<<n); for(int op=0;op<part;op++){ // cout<<"*****************"<<endl; int s = op * n;//每一部分第一个位置 mt(dp,0); for(int i=0;i<all;i++){ int yi = ONE(i); if(yi>=n) continue; for(int j=0;j<n;j++){ if((i>>j)&1) continue; //如果这一位是0 int next = i|(1<<j); dp[next] = max(dp[next],dp[i]+p[j][yi+s]); } } ans += dp[all-1]; } printf("%.5f\n",ans); } return 0; }
费用流:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<stack> #define inf 0x3f3f3f3f #define mt(a,b) memset(a,b,sizeof(a)) using namespace std; int n,m; double p[16][1024]; class MaxFlowMinCost { ///最小费用最大流 o(ME) typedef int typef;///流量的类型 typedef double typec;///费用的类型 static const int ME=1010;///边的个数 static const int MV=100;///点的个数 queue<int> q; int cur[MV],pre[MV]; bool used[MV],sign[MV]; typef flow; typec cost,dist[MV]; bool spfa(int s,int t) { mt(used,0); mt(sign,0); mt(dist,0); used[s]=sign[s]=true; while(!q.empty()) q.pop(); q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); used[u]=false; for(int i=g.head[u]; ~i; i=g.e[i].next) { if(g.e[i].flow<1) continue; int v=g.e[i].v; typec c=g.e[i].cost; if(!sign[v]||dist[v]>dist[u]+c) { dist[v]=dist[u]+c; sign[v]=true; pre[v]=u; cur[v]=i; if(used[v]) continue; used[v]=true; q.push(v); } } } return sign[t]; } struct G { struct E { int v,next; typef flow; typec cost; } e[ME]; int le,head[MV]; void init() { le=0; mt(head,-1); } void add(int u,int v,typef flow,typec cost) { e[le].v=v; e[le].flow=flow; e[le].cost=cost; e[le].next=head[u]; head[u]=le++; } } g; public: void init() { g.init(); } void add(int u,int v,typef flow,typec cost) { g.add(u,v,flow,cost); g.add(v,u,0,-cost); } void solve(int s,int t) { flow=cost=0; while(spfa(s,t)) { int temp=t; typef now=inf; while(temp!=s) { now=min(now,g.e[cur[temp]].flow); temp=pre[temp]; } flow+=now; temp=t; while(temp!=s) { int id=cur[temp]; cost+=now*g.e[id].cost; g.e[id].flow-=now; g.e[id^1].flow+=now; temp=pre[temp]; } } } typef getflow() { return flow; } typec getcost() { return cost; } } gx; int main() { int _; int Cas = 0; scanf("%d",&_); while(_--) { scanf("%d%d",&n,&m); mt(p,0); // for(int i=0;i<n;i++){ // for(int j=0;j<m+10;j++){ // p[i][j] = 0.0; // } // } for(int i=0; i<n; i++) { for(int j=0; j<m; j++) { scanf("%lf",&p[i][j]); } } // cout<<"*************"<<endl; // for(int i=0; i<n; i++) { // for(int j=0; j<m; j++) { // printf("%.2f ",p[i][j]); // } // puts(""); // } // cout<<"*************"<<endl; printf("Case #%d: ",++Cas); int part = m/n; if(m%n!=0) part++; double ans = 0.0; for(int op=0; op<part; op++) { gx.init(); int S = 2*n+1; int T = 2*n+2; int st = op * n; for(int i=0; i<n; i++) { for(int j=0; j<n; j++) { gx.add(i,j+n,1,-p[i][j+st]); } } for(int i=0; i<n; i++) { gx.add(S,i,1,0); } for(int i=0; i<n; i++) { gx.add(i+n,T,1,0); } gx.solve(S,T); ans -= gx.getcost(); } printf("%.5f\n",ans); } return 0; }
相关文章推荐
- HDU-5045 Contest 状态压缩DP求期望
- HDU 5045 Contest(概率dp,状态压缩,2014上海网络赛1004)
- HDU 5045 Contest (状态压缩dp)
- Hdu 5045 Contest (状态压缩dp)
- hdu 5045 Contest(状态压缩DP)
- hdu - 5045 - Contest(状态压缩dp)
- hdu 5045 Contest(状态压缩DP)
- Hdu 5045 Contest (2014 上海Online) (状态压缩dp)
- hdu 5045 Contest 状态压缩dp
- hdu 5045 Contest dp+状态压缩 2014 ACM/ICPC Asia Regional Shanghai Online
- [ACM] hdu 5045 Contest (状态压缩Dp)
- HDU 5045 Contest 状态压缩DP
- hdu 5045(dp + 状态压缩)
- Hdu 4057 Rescue the Rabbit (AC自动机+状态压缩dp) - 2011 ACM-ICPC Dalian Regional Contest Problem G
- 20140930 【 DP - 状态压缩 】 2014-上海区域赛-网络预选赛 hdoj 5045 Contest
- hdu 4385 Moving Bricks (状态压缩dp 2012 Multi-University Training Contest 9 )
- hdu 5045(状态压缩dp)
- hdu 4317 Unfair Nim (状态压缩DP) 【2012 Multi-University Training Contest 2】
- Contest+hdu+状态压缩dp
- HDU 3920 Clear All of Them I 状态压缩DP 2011 Multi-University Training Contest 9 - Host by BJTU