【题解】P4363 [九省联考 2018] 一双木棋 chess

原题链接

题目描述

菲菲和牛牛在一块 nm 列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手。

棋局开始时,棋盘上没有任何棋子,两人轮流在格子上落子,直到填满棋盘时结束。

落子的规则是:一个格子可以落子当且仅当这个格子内没有棋子且这个格子的左侧及上方的所有格子内都有棋子。

棋盘的每个格子上,都写有两个非负整数,从上到下第 i 行中从左到右第 j 列的格子上的两个整数记作 ai,jbi,j

在游戏结束后,菲菲和牛牛会分别计算自己的得分:菲菲的得分是所有有黑棋的格子上的 ai,j 之和,牛牛的得分是所有有白棋的格子上的 bi,j 的和。

菲菲和牛牛都希望,自己的得分减去对方的得分得到的结果最大。现在他们想知道,在给定的棋盘上,如果双方都采用最优策略且知道对方会采用最优策略,那么,最终的结果如何?

题解

轮廓线DP同时维护值和当前该哪个人走。

#include<bits/stdc++.h>
using namespace std;
inline int rd(){
	int f=1,j=0;
	char w=getchar();
	while(!isdigit(w)){
		if(w=='-')f=-1;
		w=getchar();
	}
	while(isdigit(w)){
		j=j*10+w-'0';
		w=getchar();
	}
	return f*j;
}
const int N=4000010;
int n,m,suma[11][11],sumb[11][11],f[N],g[N],vis[N];
struct node{
	int k,t;
}p[N];
int tot;
inline int si(int x){
	int cnt=0;
	while(x)cnt+=(x&1),x>>=1;
	return cnt;
}
void pri(int x){
	if(!x)return ;
	pri(x>>1);
	printf("%d",x&1);
	return ;
}
signed main(){
	n=rd(),m=rd();
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)suma[i][j]=rd();
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)sumb[i][j]=rd();
	f[(1<<n)-1]=0,g[(1<<n)-1]=(((n*m)&1)!=1),vis[(1<<n)-1]=true;
	for(int k=(((1<<n)-1)<<m);k>=0;k--){
		if(si(k)!=n)continue;
		if(k==(1<<n)-1)continue;
		int x=n+1,y=0,t=0;
		for(int j=n+m-1;j>=0;j--){
			if(k&(1<<j))x--,t+=y;
			else y++;
		}
		p[++tot]=(node){k,t};
	}
	sort(p+1,p+1+tot,[&](node a,node b){return a.t>b.t;});
	for(int t=1,k;t<=tot;t++){
		k=p[t].k;
//		pri(k),cout<<":";
		int x=n+1,y=1;
		for(int j=n+m-1;j>=0;j--){
			if(k&(1<<j))x--;
			else y++;
			if(j==0)continue;
			if(x<1||x>n||y<1||y>m)continue;
			if(!((k&(1<<j))&&!(k&(1<<(j-1)))))continue;
			int nex=k^(1<<j)^(1<<(j-1));
			g[k]=g[nex]^1;
//			cout<<"("<<x<<","<<y<<":";
//			pri(nex),cout<<"- "<<f[nex]<<" "<<((g[k])?f[nex]+suma[x][y]:f[nex]-sumb[x][y])<<")";
			if(!vis[k])f[k]=f[nex]+((g[k])?suma[x][y]:(-sumb[x][y])),vis[k]=true;
			if(g[k])f[k]=max(f[k],f[nex]+suma[x][y]);
			else f[k]=min(f[k],f[nex]-sumb[x][y]);
		}
//		cout<<"- "<<f[k]<<" "<<g[k]<<"\n";
//		pri(k),cout<<"-"<<f[k]<<" "<<g[k]<<":";
//		x=n+1,y=1;
//		for(int j=n+m-1;j>=0;j--){
//			if(k&(1<<j))x--;
//			else y++;
//			cout<<"("<<x<<","<<y<<")";
//		}
//		printf("\n");
	}
	printf("%d\n",f[(((1<<n)-1)<<m)]);
	return 0;
}
posted @   flywatre  阅读(22)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
点击右上角即可分享
微信分享提示