zoukankan      html  css  js  c++  java
  • GYM102155A A.Ability Draft 状压DP 博弈

    GYM102155A A.Ability Draft 状压DP 博弈

    题意

    有两个阵营共(2 imes n)个英雄,每个英雄可以选择(s)个普通技能和(1)个终极技能。

    两个阵容都希望自己的技能总和尽量大对方的尽量小,问最终的 阵容一 的和减去 阵容二的和

    [1 leq n leq 5,1 leq s leq 3 ]

    分析

    看数据范围容易想到状压DP

    (dp[i][j][k])表示前(i)个选择,(j,k)表示选择已经选择终极技能的情况

    以开始的做法是从第1个开始枚举是否选择终极技能,然后往下递推,但很容易发现hack这样会走到很离谱的情况,于是想到这样的正确性可能不对,正确的应该是类似搜索那样从后往前DP

    为了实现方便可以采取记忆化搜索(好像实现起来更烦)

    据大佬口胡还可以用min-max搜索(待补)

    代码

    调了很久,实在是丑爆了

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    #define int long long
    ll rd(){
    	ll x = 0;
    	int f = 1;
    	char ch = getchar();
    	while(ch < '0' || ch > '9') {
    		if(ch == '-') f = -1;
    		ch = getchar();
    	}
    	while(ch >= '0' && ch <= '9') {
    		x = x * 10 + ch - '0';
    		ch = getchar();
    	}
    	return x * f;
    }
    
    
    int dp[50][1 << 6][1 << 6];
    int p[40];
    int val1[100],val2[100];
    int n,s;
    int p1,p2;
    int INF = 1e18;
    // now = number of person haven't choose
    // now1 = current position of normal
    // now2 = current postion of specail
    //
    
    int get1(int x){
    	if(x == INF) return -INF;
    	return x;
    }
    
    int get2(int  x){
    	if(x == -INF) return INF;
    	return x;
    }
    
    int add(int x,int y){
    	if(x == INF) return INF;
    	if(x == -INF) return -INF;
    	return x + y;
    }
    
    int dfs(int now,int msk1,int msk2,int now1,int now2){
    	if(now == 2 * n * (s + 1)) return 0;
    	if(now1 > 2 * n * s || now2 > 2 * n) return INF;
    	if(dp[now][msk1][msk2] != INF && dp[now][msk1][msk2] != -INF) return dp[now][msk1][msk2];
    	int ans;
    	int ok;
    	if(p[now] <= n) ok = (msk1 >> (p[now] - 1)) & 1;
    	else ok = (msk2 >> (p[now] - n - 1)) & 1;
    	ok ^= 1;
    	ok |= (now2  >= 2 * n);
    	int okk = (now1 >= 2 * n * s);
    	if(p[now] <= n)  ans = max(max(-INF,ok ? -INF : add(get1(dfs(now + 1,msk1 ^ (1 << (p[now] - 1)),msk2,now1,now2 + 1)),val2[now2])),okk ?  -INF : add(get1(dfs(now + 1,msk1,msk2,now1 + 1,now2)) , val1[now1]));
    	else {
    		ans = min(min(INF,ok ? INF : add(get2(dfs(now + 1,msk1,msk2 ^ (1 << (p[now] - n - 1)),now1,now2 + 1)), - val2[now2])),okk ? INF : add(get2(dfs(now + 1,msk1,msk2,now1 + 1,now2)), -val1[now1]));
    	}
    	//cout << "now = " << now << " msk1 =  "<< msk1 << " msk2 = " << msk2 << " now1 = " << now1 << " now2 = " << now2 << " ok = " << ok << " okk = " << okk << "ans = " << ans << '
    ';	
    	return dp[now][msk1][msk2] = ans;
    }
    
    signed main(){
    	n = rd();
    	s = rd();
    	for(int i = 0;i < 2 * n * (s + 1);i++)
    		p[i] = rd();
    	//reverse(p,p + 2 * n * (s + 1));
    	p1 = rd();
    	for(int i = 0;i < p1;i++)
    		val1[i] = rd();
    	p2 = rd();
    	for(int i = 0;i < p2;i++)
    		val2[i] = rd();
    	for(int i = 0;i < 2 * n * (s + 1);i++){
    		int f = p[i] <= n ? -INF : INF;
    		for(int k = 0;k < (1 << 5);k++)
    			for(int j = 0;j < (1 << 5);j++)
    				dp[i][k][j] = f;
    	}
    	sort(val1,val1 + p1,greater<int>());
    	sort(val2,val2 + p2,greater<int>());
    	cout << dfs(0,(1 << n) - 1,(1 << n) - 1,0,0);
    }
    

    JianglyGG的代码

    #include <bits/stdc++.h>
    constexpr int N = 5, S = 3, T = 2 * N * (S + 1), INF = 1e9;
    int n, s, pu, ps;
    int p[T], vs[36], vu[12], dp[T + 1][1 << (2 * N)], ok[T + 1][1 << (2 * S)];
    int main() {
        std::srand(std::chrono::steady_clock::now().time_since_epoch().count());
        std::ios::sync_with_stdio(false);
        std::cin.tie(nullptr);
        std::cin >> n >> s;
        for (int i = 0; i < 2 * n * (s + 1); ++i) {
            std::cin >> p[i];
            --p[i];
        }
        std::cin >> ps;
        for (int i = 0; i < ps; ++i)
            std::cin >> vs[i];
        std::cin >> pu;
        for (int i = 0; i < pu; ++i)
            std::cin >> vu[i];
        std::sort(vs, vs + ps, std::greater<>());
        std::sort(vu, vu + pu, std::greater<>());
        ok[2 * n * (s + 1)][(1 << (2 * n)) - 1] = 1;
        for (int i = 2 * n * (s + 1) - 1; i >= 0; --i) {
            for (int j = 0; j < (1 << (2 * n)); ++j) {
                int c = __builtin_popcount(j);
                ok[i][j] = ok[i + 1][j] | ok[i + 1][j | 1 << p[i]];
                if (!ok[i][j] || c > i)
                    continue;
                if (p[i] < n) {
                    dp[i][j] = std::max(ok[i + 1][j] ? dp[i + 1][j] + vs[i - c] : -INF, (~j >> p[i] & 1) && ok[i + 1][j | 1 << p[i]] ? dp[i + 1][j | 1 << p[i]] + vu[c] : -INF);
                } else {
                    dp[i][j] = std::min(ok[i + 1][j] ? dp[i + 1][j] - vs[i - c] : INF, (~j >> p[i] & 1) && ok[i + 1][j | 1 << p[i]] ? dp[i + 1][j | 1 << p[i]] - vu[c] : INF);
                }
            }
        }
        std::cout << dp[0][0] << "
    ";
        return 0;
    }
    
  • 相关阅读:
    MemoryCache
    Page.Cache
    webform运行时弹出JavaScript的alert窗口
    server.Transfer不工作
    Server.Transfer VS Response.Redirect – Simplified
    Code Pages
    Unicode, UTF, ASCII, ANSI format differences
    Character Encoding in .NET
    分布式之消息队列复习精讲
    Understand:高效代码静态分析神器详解(一)
  • 原文地址:https://www.cnblogs.com/hznumqf/p/15024566.html
Copyright © 2011-2022 走看看