Luogu P4363 [九省联考2018]一双木棋chess

题链

分析

显然每次轮廓线都是从左下到右上,所以方案数只有\(C_{n+m}^{n}\)

暴力枚举状态,建出节点为状态的图

然后倒序DP即可

#include<bits/stdc++.h>
#define ll long long
#define pb push_back
const int INF=1e9;
using namespace std;

const int N=4e5+5;
int n,m,cnt,t[20],f[N],deg[N],a[20][20],b[20][20],num[N];
ll mi[20],S[N];
map<ll,int>mp;
struct A{int v,w;};
vector<A>V[N];
void dfs(int u,int lst,ll s) {
	if(u>n) {
		S[++cnt]=s;
		mp[s]=cnt;
		return;
	}
	for(int i=0;i<=lst;i++) {
		dfs(u+1,i,s+mi[u-1]*i);
	}
} 
void init() {
	mi[0]=1;
	for(int i=1;i<=n;i++) mi[i]=mi[i-1]*11;
	dfs(1,m,0); 
	for(int i=1;i<=cnt;i++) {
		ll s=S[i];
		for(int j=1;j<=n;j++) {
			t[j]=s%11;
			s/=11;
		}
	//	printf("%d %lld %d %d %d\n",i,S[i],t[1],t[2],num[i]);
		for(int j=1;j<=n;j++) {
			if(t[j]) {
				if(t[j]<m&&(j==1||t[j]!=t[j-1])) {
					s=S[i]+mi[j-1]; int k=mp[s];
					num[k]=!num[i];
					if(num[k]) V[k].pb((A){i,a[j][t[j]+1]});//V[i].pb((A){k,a[j][t[j]+1]});
						else V[k].pb((A){i,-b[j][t[j]+1]});//V[i].pb((A){k,-b[j][t[j]+1]});
				//	printf("%d %d\n",k,i);
				}
			} else {
			//	if(i==3) printf("%d\n",j);
				s=S[i]+mi[j-1]; int k=mp[s];
				num[k]=!num[i];
				if(num[k]) V[k].pb((A){i,a[j][1]});//V[i].pb((A){k,a[j][t[j]+1]});
					else V[k].pb((A){i,-b[j][1]});//V[i].pb((A){k,-b[j][t[j]+1]});
				//	printf("%d %d\n",k,i);
				break;
			}
		}
		f[i]=INF;
	}
}
queue<int>q;
void bfs(int s) {
	q.push(s); f[s]=0;
	while(!q.empty()) {
		int u=q.front(); q.pop();
		for(A v:V[u]) {
			if(f[v.v]==INF){
				f[v.v]=f[u]+v.w;
				q.push(v.v);
			}
			if(num[u]) f[v.v]=max(f[v.v],f[u]+v.w);
				else f[v.v]=min(f[v.v],f[u]+v.w);
		}
	}
}
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]);
	}
	init();
	bfs(cnt);
	printf("%d\n",f[1]);
	return 0;
}
posted @ 2021-06-07 23:36  wwwsfff  阅读(37)  评论(0编辑  收藏  举报