POJ 1185 经典dp

开始居然题目都理解错了,两个兵攻击范围重叠是允许的

思路都是错的,其实就是按经典的想法,解除后效性就要把相关的会影响后面的状态对应的答案都记录下来

然后就是状态压缩,学习了!!

又是偷来的代码,我太挫了!

//#include <iostream>
//#include <cstring>
//#include <cstdio>
//#include <cstdlib>
//#include <vector>
//using namespace std;
//int n,d,m;
//int vis[11][23][23];
//int dp[11][23][23];
//
//
//
//int main ()
//{
//	while(scanf("%d%d%d",&n,&d,&m)!=EOF)
//	{
//		if(n==0 && d==0 && m==0) break;
//		memset(vis,0,sizeof(vis));
//		memset(dp,0,sizeof(dp));
//		int x,y,tt;
//		int tot=0;
//		for(int i=1;i<=m;++i)
//		{
//			scanf("%d%d%d",&x,&y,&tt);
//			vis[tt][x][y]=1;
//			tot=max(tot,tt);
//		}
//		for(int i=0;i<tot;++i) // from i to i+1
//		{
//			for(int x1=0;x1<n;++x1)
//				for(int y1=0;y1<n;++y1)
//				{
//					for(int x2=x1-d;x2<=x1+d;++x2)
//						for(int y2=y1-d;y2<=y1+d;++y2)
//							if(x2>=0 && x2<n && y2>=0 && y2<n && (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)<=d*d)
//							{
//								
//							}
//				}
//		}
//	}
//	return 0;
//}

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;
char mat[105][15];
int dp[2][70][70];
int s[70],state[70],h[106],sta_num;
int n,m;


int main ()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=0;i<n;++i)
            scanf("%s",mat[i]);
        memset(dp,0,sizeof(dp));
        memset(s,0,sizeof(s));
        memset(h,0,sizeof(h));
        sta_num=0;

        for(int j=0;j<(1<<m);++j)
        {
            if(j&(j<<1) || j&(j<<2))
                continue;
			state[sta_num]=j;
            int k=j;
            do{
                s[sta_num]+=k%2;
                k=k>>1;
            }while(k);
            sta_num++;
        }
        for(int i=0;i<n;++i)
            for(int j=0;j<m;++j)
                if(mat[i][j]=='H')
                {
                    h[i]+=(1<<j);
                }
        
        int now=0;
        for(int i=0;i<n;++i)
		{
            for(int j=0;j<sta_num;++j)
            { 
				if(state[j]&h[i]) continue;
                if(i==0)
                {
                    if(dp[now][j][0]<s[j])
						dp[now][j][0]=s[j];
                }
                else if(i==1)
                {
                    for(int k=0;k<sta_num;++k)
                    {
                        if(state[k]&h[i-1] || state[j]&state[k]) 
							continue;
                        if(dp[now][j][k]<dp[(now+1)%2][k][0]+s[j])
                            dp[now][j][k]=dp[(now+1)%2][k][0]+s[j];
                    }
                }
                else
                {
                    for(int k=0;k<sta_num;++k)
                    {
                        if(state[k]&h[i-1] || state[j]&state[k])  
							continue;
                        for(int l=0;l<sta_num;++l)
                        {
                            if(state[l]&h[i-2] || state[k]&state[l] || state[j]&state[l])
								continue;
                            if(dp[now][j][k]<dp[(now+1)%2][k][l]+s[j])
                                dp[now][j][k]=dp[(now+1)%2][k][l]+s[j];
                        }
                    }
                }
            }
			now=(now+1)%2;
		}
        now=(now+1)%2;
        int ans=0;
        for(int i=0;i<sta_num;++i)
            for(int j=0;j<sta_num;++j)
                if(ans<dp[now][i][j])
					ans=dp[now][i][j];
        printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值