总和一定的博弈 记忆化搜索 uva 10891 hdu 4597 hdu 4753

UVA 10891 :

题意: 现在给你一个序列,你可以从序列的左端开始取数,也可以从序列的右端开始取数,每次可以取连续个数,A先取,问A最多比B多取多少。

思路: n为100 显然是区间dp,但是这里也可以用记忆化搜一下呀。这就是一个总和确定的博弈。遇到边界就是l>r ,或者 l==r 。

记忆化代码:

#include<bits/stdc++.h>

using namespace std;
const int inf =0x3f3f3f3f;
int dp[105][105];
int a[105];
int pre[105];
int n;

int dfs(int l,int r,int sum)
{
    if(l>r) return 0;
    if(l==r) return dp[l][r]=a[l];
    if(dp[l][r]!=-1) return dp[l][r];
    int res=-inf;
    for(int k=l;k<=r;k++){
        res=max(res,sum-dfs(k+1,r,sum-(pre[k]-pre[l-1])));
    }
    for(int k=r;k>=l;k--){
        res=max(res,sum-dfs(l,k-1,sum-(pre[r]-pre[k-1])));
    }
    return dp[l][r]=res;
}

int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0) break;
        memset(dp,-1,sizeof(dp));
        int sum=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            sum+=a[i];
        }
        for(int i=1;i<=n+2;i++){
            if(i>n) pre[i]=0;
            else pre[i]=pre[i-1]+a[i];
        }

        int ans=dfs(1,n,sum);
        int b=sum-ans;
        printf("%d\n",ans-b);
    }
    return 0;
}

/*

4
4 -10 -20 7
4
1 2 3 4
0

*/

区间dp代码:

#include<bits/stdc++.h>
#define N 105
#define inf 0x3f3f3f3f

using namespace std;

int dp[N][N];
int a[N];
int sum[N];
int n;

int main()
{
	while(scanf("%d",&n)!=EOF)
	{
		if(n==0) break;
		for(int i=1;i<=n;i++) scanf("%d",&a[i]);
		memset(sum,0,sizeof(sum));
		for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i];
		
		memset(dp,0,sizeof(dp));
		
		for(int i=1;i<=n;i++) dp[i][i]=a[i];
		
		for(int len=2;len<=n;len++)
		{
			for(int i=1;i+len-1<=n;i++)
			{
				int j=i+len-1;
				
				int res=0;  // 表示全部拿完 
				int ssum=sum[j]-sum[i-1];
				for(int k=i;k<=j;k++) res=min(res,dp[k][j]);
				for(int k=j;k>=i;k--) res=min(res,dp[i][k]);
				
				dp[i][j]=ssum-res;
			}
		}
		
		/*
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++) printf("%d ",dp[i][j]);
			printf("\n");
		}
		*/
		int ans=dp[1][n]-(sum[n]-dp[1][n]);
		printf("%d\n",ans);
	}
	
	return 0;
} 

hdu 4597:

题意:现在给你两个序列,你每次可以在两个序列的四个端点随便选择一个数,那么问你先手最多拿多少。

和上边题神似,直接记忆化搜就可以了。

代码:

#include<bits/stdc++.h>

using namespace std;
const int N =25;
int a[N];
int b[N];
int dp[25][25][25][25];
int ans[N];
int n;

int dfs(int la,int ra,int lb,int rb,int sum)
{
    if(la>ra&&lb>rb) return 0;
    if(dp[la][ra][lb][rb]!=-1) return dp[la][ra][lb][rb];
    int res=0;
    if(la<=ra)
    {
        res=max(res,sum-dfs(la+1,ra,lb,rb,sum-a[la]));
        res=max(res,sum-dfs(la,ra-1,lb,rb,sum-a[ra]));
    }
    if(lb<=rb){
        res=max(res,sum-dfs(la,ra,lb+1,rb,sum-b[lb]));
        res=max(res,sum-dfs(la,ra,lb,rb-1,sum-b[rb]));
    }
    return dp[la][ra][lb][rb]=res;
}


int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=1;i<=n;i++) scanf("%d",&b[i]);
        int sum=0;
        for(int i=1;i<=n;i++) sum+=(a[i]+b[i]);
        memset(dp,-1,sizeof(dp));
        int Ans=dfs(1,n,1,n,sum);
        cout<<Ans<<endl;

    }
    return 0;
}

hdu 4753

题意: 现在有一个九宫格,24条边,A和B轮流加一条边,我如果加了这条边形成了1个1*1的小正方形,那么我得分+1 如果形成了两个,那么得分+2.问你最后谁的得分更高一些。

扫描二维码关注公众号,回复: 3391927 查看本文章

思路: 因为已经给了你>=12条已经加上的边,所以直接对没有加进去的边状压(不会超过12个)然后搜索一下。

真的傻逼,明明错了却不知道改最容易错的地方,结果改的实在觉得没错了,才他妈想起来是不是预处理。。数字搞错了。

代码:

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<int ,int > pii;
const int N =27;
int vis[N][N];

map<pii,int >id;
int mp[N][N];
map<int ,pii>mp1;
int dp[(1<<14)];
int yi[25];
int n;

void init_yi()
{
    yi[0]=1;
    for(int i=1;i<=21;i++) yi[i]=yi[i-1]*2;
}

void init()
{
    int tot=0;
    mp[1][2]=1,mp[2][3]=2,mp[3][4]=3;
    mp[1][5]=4,mp[2][6]=5,mp[3][7]=6,mp[4][8]=7;
    mp[5][6]=8,mp[6][7]=9,mp[7][8]=10;
    mp[5][9]=11,mp[6][10]=12,mp[7][11]=13,mp[8][12]=14;
    mp[9][10]=15,mp[10][11]=16,mp[11][12]=17;
    mp[9][13]=18,mp[10][14]=19,mp[11][15]=20,mp[12][16]=21;
    mp[13][14]=22,mp[14][15]=23,mp[15][16]=24;
    for(int i=1;i<=16;i++){
        for(int j=1;j<=16;j++){
            if(mp[i][j]!=0){
                mp1[++tot]=pii(i,j);
            }
        }
    }
}

int jud1()
{
    if(vis[1][2]&&vis[1][5]&&vis[2][6]&&vis[5][6]) return 1;
    return 0;
}
int jud2()
{
    if(vis[2][3]&&vis[2][6]&&vis[3][7]&&vis[6][7]) return 1;
    return 0;
}

int jud3()
{
    if(vis[3][4]&&vis[3][7]&&vis[4][8]&&vis[7][8]) return 1;
    return 0;
}
int jud4()
{
    if(vis[5][6]&&vis[5][9]&&vis[6][10]&&vis[9][10]) return 1;
    return 0;
}

int jud5()
{
    if(vis[6][7]&&vis[6][10]&&vis[10][11]&&vis[7][11]) return 1;
    return 0;
}

int jud6()
{
    if(vis[7][8]&&vis[7][11]&&vis[11][12]&&vis[8][12]) return 1;
    return 0;
}
int jud7()
{
    if(vis[9][10]&&vis[9][13]&&vis[13][14]&&vis[10][14]) return 1;
    return 0;
}
int jud8()
{
    if(vis[10][11]&&vis[10][14]&&vis[11][15]&&vis[14][15]) return 1;
    return 0;
}
int jud9()
{
    if(vis[11][15]&&vis[11][12]&&vis[15][16]&&vis[12][16]) return 1;
    return 0;
}

int jud(int x,int y)
{
    //cout<<"x "<<x<<" y "<<y<<endl;
    int id=mp[x][y];
    //cout<<" id "<<id<<endl;
    int tmp=0;
    if(id==1||id==4||id==5||id==8){
        tmp+=jud1();
    }
    if(id==2||id==5||id==6||id==9){
        tmp+=jud2();
    }
    if(id==3||id==6||id==7||id==10){
        tmp+=jud3();
    }
    if(id==8||id==11||id==12||id==15){
        tmp+=jud4();
    }
    if(id==9||id==12||id==13||id==16){
        tmp+=jud5();
    }
    if(id==10||id==13||id==14||id==17){
        tmp+=jud6();
    }

    if(id==15||id==18||id==19||id==22){
        tmp+=jud7();
    }
    if(id==16||id==19||id==20||id==23){
        tmp+=jud8();
    }
    if(id==17||id==20||id==21||id==24){
        tmp+=jud9();
    }
    return tmp;
}

int up;

int dfs(int s,int sum)
{
    //cout<<"s "<<s<<" sum "<<sum<<endl;
    /*
    if(s==up){
        //cout<<".lalalal "<<endl;
        return 0;
    }
    */
    if(dp[s]!=-1) return dp[s];
    int res=0;
    for(int i=1;i<=24;i++){
        int x,y;
        x=mp1[i].first; y=mp1[i].second;
        if(vis[x][y]) continue;
        int idd=yi[id[pii(x,y)]];
        if((s&idd)==0){
            vis[x][y]=1;
            int tmps=(s|idd);
            res=max(res,sum-dfs(tmps,sum-jud(x,y)));
            vis[x][y]=0;
        }
    }
    return dp[s]=res;
}

int main()
{
    init();
    init_yi();
    int T;
    scanf("%d",&T);
    int kk=0;
    int x,y;
    int A,B;


    while(T--){
        scanf("%d",&n);
        A=0; B=0;
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=n;i++){
            scanf("%d %d",&x,&y);
            if(x>y) swap(x,y);
            vis[x][y]=1;
            int ju=jud(x,y);
            if(ju!=0){
                if(i%2==1) A+=ju;
                else B+=ju;
            }
        }
        if(A>=5||B>=5){
            if(A>=5){
                printf("Case #%d: Tom200\n",++kk);
            }
            else printf("Case #%d: Jerry404\n",++kk);
            continue;
        }

        int sum=9-(A+B);
        int tot=0;
        id.clear();
        for(int i=1;i<=24;i++){
            x=mp1[i].first; y=mp1[i].second;
            if(x>y) swap(x,y);
            if(vis[x][y]) continue;
            id[pii(x,y)]=tot++;
            //cout<<"x "<<x<<" y "<<y<<" id "<<tot<<endl;
        }
        up=yi[tot]-1;
        memset(dp,-1,sizeof(dp));
        int ans=dfs(0,sum);
        //cout<<"ans "<<ans<<endl;
        if((n+1)%2==1){
            A+=ans;
            B=9-A;
        }
        else{
            B+=ans;
            A=9-B;
        }
        //cout<<"A "<<A<<" B "<<B<<endl;
        if(A>B){
            printf("Case #%d: Tom200\n",++kk);
        }
        else printf("Case #%d: Jerry404\n",++kk);
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/yjt9299/article/details/82621092