随笔-68  评论-10  文章-0  trackbacks-0
这到题我是用压缩DP做的,但是要是n再大一些就不能这么做了。每一行取或不取分别用1、0来表示。那么我们可以用二进制来表示每行的状态。状态转移方程为:f[i][j]=max{f[i-1][k]+sum(i,j),k为第i-1行的一个状态,且j&k==0},sum(i,j)表示第i行满足状态j的数之和。对于每行的状态不能连续出现两个或多个1,因此可以把这种状态舍去。最后用滚动数组。详细见代码:
#include<iostream>
using namespace std;
int n;
int map[21][21];
int dp[2][1<<20+1];
int s[1<<20+1];
int bit[21];

int main()
{
    
int i,j,k;
    bit[
1]=1;
    
for(i=1;i<n;i++) bit[i+1]=1<<i;
    
    
int top=0;
    
for(i=0;i<(1<<20);i++)
    
{
        
for(j=1;j<20;j++)
        
{
            
if((i&(1<<(j-1)))&&(i&(1<<j)))
                
break;
        }

        
if(j==20) s[top++]=i;
    }


    
while(scanf("%d",&n)!=EOF)
    
{
        
int ans=0;
        
for(i=1;i<=n;i++)
            
for(j=1;j<=n;j++)
                scanf(
"%d",&map[i][j]);
        
        memset(dp,
0,sizeof(dp));
        
        
for(i=1;i<=n;i++)
        
{
            
for(j=0;j<top;j++)
            
{
                 
int temp=0;
                 
if(s[j]>=(1<<n)) break;
                 
for(k=1;k<=n;k++)
                 
{
                     
if(s[j]&(1<<(k-1)))
                         temp
+=map[i][k];
                 }

                 
int minn=0;
                 
for(k=0;k<top;k++)
                 
{
                     
if(s[k]>=(1<<n)) break;
                     
if((s[k]&s[j])==0)
                     
{
                         
if(minn<dp[(i-1)&1][k])
                             minn
=dp[(i-1)&1][k];
                     }

                 }

                 dp[i
&1][j]=minn+temp;
                 
if(ans<dp[i&1][j]) ans=dp[i&1][j];
            }

        }

        printf(
"%d\n",ans);
    }

    
return 0;
}

posted on 2010-08-12 21:08 wuxu 阅读(346) 评论(0)  编辑 收藏 引用 所属分类: 动态规划

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理