zoukankan      html  css  js  c++  java
  • HDU 6196 happy happy happy 爆搜加剪枝

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6196

    题意:给你长度为n的序列,爸爸和儿子玩一个游戏,儿子先手,儿子每次都选择最左边与最右边最大的那个拿走(若左右相等拿左边),爸爸可以任意拿最左边或者最右边。

    解法:膜一发题解:http://blog.csdn.net/snowy_smile/article/details/77929954

    首先,我们DP两个东西——
    1, mx[l][r]表示对于区间[l, r],儿子先手,爸爸所能拿到的最大价值差值(差值是爸爸减儿子)
    2, mn[l][r]表示对于区间[l, r],儿子先手,爸爸所能拿到的最小价值差值(差值是爸爸减儿子)
    
    那么——
    我们尝试使用搜索解决这个问题
    
    dfs(l, r, dif)表示当前还没有取的区间范围是[l, r],儿子先手,此时爸爸减儿子的差值为dif。
    
    那么——
    1,这时先考虑剪枝——
    
    	设置初始ANS = -inf;
    	
    	void dfs(int l, int r, int dif)
    	{
    		if (dif + mn[l][r] >= 0) return;	//哪怕取一个最小值,都会赢了儿子,是个无效状态
    		if (dif + mx[l][r] <= ANS) return;	//哪怕取一个最大值,差值都依然太小了,最优性剪枝
    		if (dif + mx[l][r] < 0)				//取一个最大值,使得差值尽可能小,最优性剪枝
    		{
    			gmax(ANS, dif + mx[l][r]);
    		}
    	}
    
    2,再模拟儿子的操作,获得新的(l, r, dif)
    
    3,接着需要进一步地考虑爸爸的操作——
    	<1>取l,变成dfs(l + 1, r, dif + a[l]);
    	<2>取r,变成dfs(l, r - 1, dif + a[r]);
    
    4,考虑如何获得DP数组mn[][]和mx[][]——
    
    mn[i][i - 1] = mx[i][i - 1] = 0;
    
    for(int l = n; l >= 1; --l)
    {
    	for(int r = l; r <= n; ++r)
    	{
    		先模拟儿子的操作,获得新的(ll, rr)
    		然后考虑父亲的操作——
    		1,取ll:
    			gmax(mx[l][r], a[ll] + mx[ll + 1][rr]);
    			gmin(mn[l][r], a[ll] + mn[ll + 1][rr]);
    		2,取rr:
    			gmax(mx[l][r], a[rr] + mx[ll][rr - 1]);
    			gmin(mn[l][r], a[rr] + mn[ll][rr - 1]);
    
    	}
    }
    
    题解摘自上面的博客,我直接搜索T了。然后加入桑心病况的卡时间的剪枝,可以跑到0ms。。。orz

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 110;
    const int inf = 0x3f3f3f3f;
    //mx[l][r]表示对于区间[l,r],儿子先手,爸爸能拿到的最大价值差值(差值是爸爸减去儿子)
    //mn[l][r]表示对于区间[l,r],儿子先手,爸爸能拿到的最小价值差值(差值是爸爸减去儿子)
    int LIM = 0.5*CLOCKS_PER_SEC;
    int ST;
    int n, a[maxn], mn[maxn][maxn], mx[maxn][maxn];
    void pre_deal(){
        memset(mn, 0x7f, sizeof(mn));
        memset(mx, 0x80, sizeof(mx));
        for(int i=1; i<=n+1; i++) mn[i][i-1]=mx[i][i-1]=0;
        for(int l=n; l>=1; l--){
            for(int r=l; r<=n; r++){
                int newl=l, newr = r, sub;
                if(a[newl]>=a[newr]) sub=a[newl++];
                else sub=a[newr--];
                mx[l][r] = max(mx[l][r], a[newl]+mx[newl+1][newr]-sub);
                mx[l][r] = max(mx[l][r], a[newr]+mx[newl][newr-1]-sub);
                mn[l][r] = min(mn[l][r], a[newl]+mn[newl+1][newr]-sub);
                mn[l][r] = min(mn[l][r], a[newr]+mn[newl][newr-1]-sub);
            }
        }
    }
    int ans;
    void dfs(int l, int r, int dif)
    {
        if(l>r){
            ans = max(ans, dif);
            return;
        }
        if(dif+mn[l][r]>=0) return;
        if(dif+mx[l][r]<=ans) return;
        if(dif+mx[l][r]<0){
            ans = max(ans, dif+mx[l][r]);
            return;
        }
        if(clock()-ST>LIM) return;
        int sub;
        if(a[l]>=a[r]) sub=a[l++];
        else sub=a[r--];
        dfs(l+1, r, dif+a[l]-sub);
        dfs(l, r-1, dif+a[r]-sub);
    }
    int main()
    {
        while(~scanf("%d", &n))
        {
            for(int i=1; i<=n; i++) scanf("%d", &a[i]);
            pre_deal();
            ST = clock();
            ans = -inf;
            dfs(1, n, 0);
            if(ans == -inf){
                puts("The child will be unhappy...");
            }else{
                printf("%d
    ", -ans);
            }
        }
        return 0;
    }
    


  • 相关阅读:
    No.1
    JS二叉树的操作
    JS实现快排
    BOM中的各种height
    innerHTML outerHTML innerText value 区别
    【转载】JS中DOM操作汇总
    【转载】轻松理解JS闭包
    【转载】JavaScript模块入门
    【转载】JavaScript模块简介
    【转载】浏览器缓存详解:expires cache-control last-modified
  • 原文地址:https://www.cnblogs.com/spfa/p/7544130.html
Copyright © 2011-2022 走看看