• BZOJ 5248: [2018多省省队联测]一双木棋


    题目大意:

    一个网格,两个人轮流放棋子,一个格子能放当且仅当这个格子的左面和上面已经填满。两个人每放一个格子都会获得相应的得分。

    目标:自己得分-对方得分尽可能大。

    问最终得分差。

    题解:
    状压DP,用0/1来表示轮廓线。

    代码:

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int n,m,f[1<<20][2],a[15][15],b[15][15];
    int dfs(int s,int cas){
    	if (cas==0 && f[s][cas]!=-1e9) return f[s][cas];
    	else if (cas==1 && f[s][cas]!=1e9) return f[s][cas];
    	int ans;
    	if (cas==0) ans=-1e9;
    	else ans=1e9;
    	int x=n+1,y=1;
    	if (s&(1<<(n+m-1))) x--;
    	else y++;
    	for (int i=2; i<=n+m; i++){
    		int pre=s&(1<<(n+m-i+1));
    		int now=s&(1<<(n+m-i));
    		if (pre && !now){
    			int to=s-(1<<(n+m-i+1))+(1<<(n+m-i));
    			if (cas==0) ans=max(ans,a[x][y]+dfs(to,1));
    			else ans=min(ans,dfs(to,0)-b[x][y]);
    		}
    		if (now) x--;
    		else y++;
    	}
    	f[s][cas]=ans;
    	return ans;
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for (int i=1; i<=n; i++)
    		for (int j=1; j<=m; j++)
    			scanf("%d",&a[i][j]);
    	for (int i=1; i<=n; i++)
    		for (int j=1; j<=m; j++)
    			scanf("%d",&b[i][j]);
    	int s=0;
    	for (int i=1; i<=n; i++){
    		s=s<<1;
    		s|=1;
    	}
    	for (int i=1; i<=m; i++) s=s<<1;
    	for (int i=0; i<(1<<n+m); i++) f[i][0]=-1e9,f[i][1]=1e9;
    	int t=0;
    	for (int i=1; i<=n; i++){
    		t=t<<1;
    		t|=1;
    	}
    	f[t][0]=f[t][1]=0;
    	printf("%d
    ",dfs(s,0));
    	return 0;
    }
    

      

  • 相关阅读:
    Android将ScrollView移动到最底部
    Android权限之sharedUserId和签名
    python接口使用及工具函数
    python模块(json、os、sys、random、string、time、hashlib)
    python内置函数
    python模块、函数变量及递归
    python数据类型集合及函数
    python文件操作及修改
    python字符类型操作及文件操作
    jmeter压测
  • 原文地址:https://www.cnblogs.com/silenty/p/8778602.html
Copyright © 2020-2023  润新知