http://acm.hdu.edu.cn/showproblem.php?pid=5045
1 2 3 0.6 0.3 0.4 0.3 0.7 0.9
Case #1: 2.20000
#include<cstdio> #include<iostream> #include <string.h> using namespace std; const int oo=1e9; const int mm=11111; const int mn=888; int node,src,dest,edge; int ver[mm],flow[mm],next[mm]; double cost[mm],dis[mn]; int head[mn],p[mn],q[mn],vis[mn]; void prepare(int _node,int _src,int _dest) { node=_node,src=_src,dest=_dest; for(int i=0; i<node; ++i)head[i]=-1,vis[i]=0; edge=0; } void addedge(int u,int v,int f,double c) { ver[edge]=v,flow[edge]=f,cost[edge]=c,next[edge]=head[u],head[u]=edge++; ver[edge]=u,flow[edge]=0,cost[edge]=-c,next[edge]=head[v],head[v]=edge++; } bool spfa() { int i,u,v,l,r=0; double tmp; for(i=0; i<node; ++i) dis[i]=oo; dis[q[r++]=src]=0; p[src]=p[dest]=-1; for(l=0; l!=r; (++l>=mn)?l=0:l) for(i=head[u=q[l]],vis[u]=0; i>=0; i=next[i]) if(flow[i]&&dis[v=ver[i]]>(tmp=dis[u]+cost[i])) { dis[v]=tmp; p[v]=i^1; if(vis[v])continue; vis[q[r++]=v]=1; if(r>=mn)r=0; } return p[dest]>-1; } double SpfaFlow() { int i,delta; double ret=0; while(spfa()) { for(i=p[dest],delta=oo; i>=0; i=p[ver[i]]) if(flow[i^1]<delta)delta=flow[i^1]; for(i=p[dest]; i>=0; i=p[ver[i]]) flow[i]+=delta,flow[i^1]-=delta; ret+=delta*dis[dest]; } return ret; } int n,m,T; double num[15][1005]; int main() { int tt=0; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); memset(num,0,sizeof(num)); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%lf",&num[i][j]); double sum=0; for(int k=0;k<=m/n;k++) { prepare(n*2+2,0,n*2+1); for(int i=1;i<=n;i++) { addedge(src,i,1,0); addedge(i+n,dest,1,0); for(int j=1;j<=n;j++) addedge(i,j+n,1,-num[i][j+k*n]); } sum+=(-SpfaFlow()); } printf("Case #%d: %.5lf\n",++tt,sum); } return 0; }
DP+状态压缩。dp[i][j]表示前i道题目j个人答题状态的最大值,j用二进制表示,因为人最多就10个。因为每两个人之间答题数目不能超过1,所以当状态达到1 << n - 1,即所有人都答过一题时,将重置为0。
#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; int m,n; double a[15][1250],dp[1205][1250]; int main() { int T,tt=0; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); for(int i=0;i<n;i++) for(int j=0;j<m;j++) scanf("%lf",&a[i][j]); for(int i=0;i<=m;i++) for(int j=0;j<1<<n;j++) dp[i][j]=-1.0; dp[0][0]=0; for(int i=0;i<m;i++) { for(int j=0;j<(1<<n);j++) { if(dp[i][j]<0) continue; for(int k=0;k<n;k++) { if(!((1<<k)&j)) { int st=j|(1<<k); if(st==(1<<n)-1) st=0; dp[i+1][st]=max(dp[i+1][st],dp[i][j]+a[k][i]); } } } } /*for(int i=0;i<10;i++) { for(int j=0;j<10;j++) printf("%lf ",dp[i][j]); printf("\n"); }*/ double ans=0; for(int i=0;i<(1<<n);i++) ans=max(ans,dp[m][i]); printf("Case #%d: %.5lf\n",++tt,ans); } return 0; } /** 99 3 4 0.4 0.8 0.1 0.1 0.3 0.7 0.1 0.1 0.5 0.6 0.1 0.1 3 4 0.3 0.6 0.1 0.1 0.5 0.8 0.1 0.1 0.4 0.7 0.1 0.1 2 3 0.6 0.3 0.4 0.3 0.7 0.9 ANSWER:1.5,1.4,2.2 **/