这几场比赛都没有网络流和一些模板图论,导致刚看到这题时直接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;
}