这几场比赛都没有网络流和一些模板图论,导致刚看到这题时直接YY成了最小割。。。后来被师哥提示是状态压缩DP。
(居然有神牛真用网络流过了。。。 http://www.cnblogs.com/kirk/archive/2011/09/18/2180697.html)
类似炮兵阵地的压缩DP,直接暴力会TLE,还是要初始化下由上一行状态导出的合法状态。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn=1<<10; const int maxm=15; const int inf = 0x7ffffff; int dp[maxn+123][maxm]; int n,m; int p[maxm],v[maxm][maxm],b[maxm][maxm]; int max_; int opt[maxn+123][maxm]; int val[maxn+123][maxn+123]; bool valid(int pre , int st) { return (pre&st)==st; } int DP() { max_=-inf; for (int i=0 ; i<(1<<n) ; ++i) { for (int j=0 ; j<m ; ++j) { dp[i][j]=-inf; } } memset (opt , 0 , sizeof(opt)); //遍历第r行时,第i个状态的人数的花费; for (int r=0 ; r<m ; ++r) { for (int i=0 ; i<(1<<n) ; ++i) { for (int j=0 ; j<n ; ++j) { if(i&(1<<j)) { opt[i][r]+=v[j][r]-p[r]; /*opt的更新还可以优化,不过对时间上贡献没有多大意义*/ for (int k=j+1 ; k<n ; ++k) { if(i&(1<<k))opt[i][r]+=b[k][j]; } }// end if } //printf("ooo ppp ttt %d %o %d\n",opt[i][r] , i ,r); } } for (int i=0 ; i<(1<<n) ; ++i) { dp[i][0]=opt[i][0]; max_=max(dp[i][0],max_); } for (int r=1 ; r<m ; ++r) for (int i=0 ; i<(1<<n) ; ++i)//st { for (int k=1 ; k<val[i][0] ; ++k) { int j=val[i][k]; dp[j][r]=max(dp[i][r-1]+opt[j][r],dp[j][r]); max_=max(dp[j][r],max_); } //printf("ddd ppp %d pre=%d st=%d \n",dp[i][r] , j , i); } return max_; } void init () { memset(val , 0 , sizeof(val)); for (int i=0 ; i<maxn ; ++i) { int cnt=0; for (int j=0 ; j<maxn ; ++j) { if(valid(i,j)) { ++cnt; val[i][cnt]=j; } } val[i][0]=cnt+1; } } int main () { init(); while (scanf("%d%d",&n,&m),n||m) { for (int i=0 ; i<m ; ++i) { scanf("%d",p+i); } for (int i=0 ; i<n ; ++i) { for (int j=0 ; j<m ; ++j) { scanf("%d",*(v+i)+j); } } for (int i=0 ; i<n ; ++i) { for (int j=0 ; j<n ; ++j) { scanf("%d",*(b+i)+j); } } int ans=DP(); if(ans)printf("%d\n",ans); else printf("STAY HOME\n"); } return 0; }
网络流的解法:
Rank | Author | Exe. Time | Exe. Memory | Code Len. | Language | Date |
1 | Geners | 0MS | 280K | 3550B | C++ | 2011-09-21 20:34:35 |
最大权闭合图,又进一步理解了用图来表示必要关系
#include <cstdio> #include <cstring> const int maxn=1005; const int inf=1<<25; const int s=0; struct edge{ int v,next,w; }edge[maxn*maxn]; int head[maxn],cnt;//for sap void addedge(int u, int v, int w) { edge[cnt].v=v; edge[cnt].w=w; edge[cnt].next=head[u]; head[u]=cnt++; edge[cnt].v=u; edge[cnt].w=0; edge[cnt].next=head[v]; head[v]=cnt++; } int sap(int t) { int pre[maxn],cur[maxn]; int dis[maxn],gap[maxn]; int flow=0 , aug=inf ,u; bool flag; for (int i=0 ; i<=t ; ++i) { cur[i]=head[i]; gap[i]=dis[i]=0; } gap[s]=t+1; u=pre[s]=s; while (dis[s]<=t) { flag=0 ; for (int &j=cur[u] ; ~j ; j=edge[j].next) { int v=edge[j].v; if (edge[j].w>0 && dis[u]==dis[v]+1) { flag=1; if(edge[j].w<aug)aug=edge[j].w; pre[v]=u; u=v; if (u==t) { flow+=aug; while (u!=s) { u=pre[u]; edge[cur[u]].w-=aug; edge[cur[u]^1].w+=aug; } aug=inf; } break; } } if (flag)continue ; int mindis=t+1; for (int j=head[u]; ~j ; j=edge[j].next) { int v=edge[j].v; if (edge[j].w>0 && dis[v]<mindis) { mindis=dis[v]; cur[u]=j; } } if(--gap[dis[u]]==0)break; gap[dis[u]=mindis+1]++; u=pre[u]; } return flow; } const int N=15; int n,m; int p[N]; int v[N][N]; int b[N][N]; int sum; void build_graph() { for (int i=0 ; i<n ; ++i) { for (int j=0 ; j<m ; ++j) { if(v[i][j]>0)addedge(0 , j*100+i+1 , v[i][j]),sum+=v[i][j]; if(v[i][j]<0)addedge(j*100+i+1 , 1002 , -v[i][j]); //printf("0 , %d , 1002 \n" , j*100+i+1); for (int k=0 ; k<i ; ++k) { sum+=b[i][k]; addedge(0 , j*100+i+1+10+k*10 , b[i][k]); addedge(j*100+i+1+10+k*10 , j*100+i+1 , inf); addedge(j*100+i+1+10+k*10 , j*100+k+1 , inf); //printf("%d , \n" , j*100+i+1+10+k*10); } if(j>0) { addedge((j)*100+i+1 , (j-1)*100+i+1 , inf); //printf("%d === %d \n", j , j+1); } } } } int main () { while (scanf("%d%d",&n,&m) , n||m) { memset (head , -1 , sizeof(head)); cnt=0; for (int i=0 ; i<m ; ++i) { scanf("%d",p+i); } for (int i=0 ; i<n ; ++i) { for (int j=0 ; j<m ; ++j) { scanf("%d",*(v+i)+j); v[i][j]-=p[j]; } } for (int i=0 ; i<n ; ++i) { for (int j=0 ; j<n ; ++j) scanf("%d",*(b+i)+j); } sum=0; build_graph(); int ans=sum-sap(1002); //printf("---%d\n",ans); if(ans)printf("%d\n",ans); else puts("STAY HOME"); } return 0; }