2020暑期牛客多校训练营第八场(C)Cinema(状压DP,离散化)

Cinema

原题请看这里

题目描述:

中国的电影院在关闭六个月后将重新开放,以帮助减缓冠状病毒的传播。
阿波罗的电影院有 n n 排座位,每排有 m m 个座位
行。我们将第 x x 行和第 y y 列上的座位表示为一对数字 ( x y ) (x,y) 。根据该政策,电影院中的人们需要保持社交距离。因此,两个人不能坐在相邻的两个座位上。
如果两个席位 ( x 1 y 1 ) ( x 2 y 2 ) (x_1,y_1)(x_2,y_2) 具有相同的边缘,则认为它们是相邻的,
x 1 x 2 + y 1 y 2 = 1 | x_1-x_2 | + | y_1-y_2 | = 1
人们将来到票房一张一张地买票,并允许他们自己选择座位。人们可以选择任何有效的座位。如果不是由其他人选择并且不与其他人相邻的座位,则该座位有效。如果没有有效的座位,电影院收银员将停止出售门票。作为电影院的老板,阿波罗想知道最坏情况下可以出售的最低票数。我们可以假设有足够的人来购买门票(即电影院收银员将继续出售门票,直到没有有效的座位为止)。

输入描述:

输入的第一行给出测试用例的数量 T ( 1 T 1000 ) \mathbf {T}(1 \leq \mathbf {T} \leq 1000) T \mathbf {T} 组测试用例如下。
每个测试用例由一行包含两个整数 n ( 1 n 1000 ) n(1 \le n \le 1000) m ( 1 m 15 ) m(1 \le m \le 15) 组成,分别表示行数和列数。

输出描述:

对于每个测试用例,输出一行包含 C a s e Case # x x y y ,其中 x x 是测试用例编号(从 1 1 开始), y y 是在最坏情况下可以出售的最小票数。 然后,再打印 n n 行,每行 m m 个字符,表示只能卖 y y 张电影票的情况。 “ *”表示已选择座位“.” 表示未选择座位。
如果有多个有效答案,则可以输出其中任何一个。

样例输入:

3
3 3
4 5
1 5

样例输出:

Case #1: 3
*.*
...
.*.
Case #2: 6
..*.*
*....
...*.
.*..*
Case #3: 2
.*.*.

思路:

状压 d p dp 看到m的取值范围就想到状压了
首先我们考虑一般的状压怎么写:0表示这个位子没有人,1表示这个位子没有人。
可是我们脑袋一拍可以知道这两种肯定不够,如果是求最多,那么两种就足够了。
一个位子可以贡献四个位子不能坐人,如果两个位子的贡献重合了,那肯定是不划算的,所以我们还要存这个位子周围是否有人,于是我们重新定义状压的写法:

  • 0表示这个位子没有人,且周围的四个位子也没有人
  • 1表示这个位子没有人但周围的四个位子(不一定都有人)有人
  • 2表示这个位子有人

这时我们的任务已经完成一大半了:一个三进制的状压。但是一看数据范围,我们发现 3 15 1000 3^{15}*1000 直接炸了…更何况还有 1000 1000 组数据。
于是接下来我们的任务就是:怎样压缩数据。
如果有刷题广的人做过这题:方格取数,就会发现:这题的情况和本题类似,都需要压缩数据。在 d p dp 数组中存的状态是否都是有用的呢?显然不是,比如说如果两个2相邻,那么就不用考虑了,所以,我们需要进行一个操作:离散化。
在同一行内有许多不合法的情况可以筛除:

  • 两个2相邻
  • 一个0和一个2相邻
  • 两个0相邻
  • 两个相邻的1且周围没有2

所以我们只要预处理每一个m的不合法情况进行剔除,就不会爆了。

A C AC C o d e Code :

#include<bits/stdc++.h>
#define ll long long
using namespace std;
struct node{
	int first;
	int second;
	node(){}
	node(int _f,int _s){first=_f,second=_s;}
	bool operator < (const node &n1)const{
		return first<n1.first;
	}
};
const int MAXM=16;
const int MAXX=1005;
const int MAXN=6600;
const int MAX=13e6+5;
int qm[MAXX],sta[MAXN],id[MAX],dp[MAXX][MAXN];
int pre[MAXX][MAXN],num2[MAXN],num0[MAXN],ans[MAXN];
int tot,t,n,m;
vector<node> vec[MAXN];
vector<int> nxt[MAXN],sol[MAXN];
void dfs(int pos,int now,int mm){
	if(pos==mm){
		if(pos>=2&&(now%3==1)&&(now/3%3==1)&&(pos-2<0||now/9%3!=2))return;
		id[now]=tot;sta[tot++]=now;return;
	}if(!pos){
		dfs(pos+1,now*3,mm);
		dfs(pos+1,now*3+1,mm);
		dfs(pos+1,now*3+2,mm);
		return;
	}if(now%3^1){dfs(pos+1,now*3+1,mm);return;}
	dfs(pos+1,now*3+2,mm);
	if(!(pos>=2&&(now%3==1)&&now/3%3==1&&(pos-2<0||now/9%3!=2))){
		dfs(pos+1,now*3,mm);
		dfs(pos+1,now*3+1,mm);
	}
}int get2(int x){
	int ret=0;
	while(x){ret+=(x%3==2);x/=3;}
	return ret;
}int get0(int x,int mm){
	int ret=0;
	for(int i=0;i<mm;++i){ret+=(x%3==0);x/=3;}
	return ret;
}void search(vector<int> &res,int a[],int mm,int now,int pos){
	if(pos>=mm){res.push_back(now);return;}
	if(a[pos]==2) search(res,a,mm,now*3+1,pos+1);
	else if(!a[pos]){
		if(pos+1<mm) search(res,a,mm,(now*3+2)*3+1,pos+2);
		else search(res,a,mm,now*3+2,pos+1);
	}else{
		if(pos+1<mm){
			if(!a[pos+1]) search(res,a,mm,now*3+1,pos+1);
			else if(a[pos+1]==2){
				search(res,a,mm,now*3,pos+1);
				search(res,a,mm,now*3+2,pos+1);
			}else{
				if(pos+2>=mm||a[pos+2]==2){
					search(res,a,mm,(now*3+2)*3+1,pos+2);
					search(res,a,mm,(now*3+1)*3+2,pos+2);
				}else if(!a[pos+2]){
					search(res,a,mm,now*9+1,pos+2);
					search(res,a,mm,(now*3+2)*3+1,pos+2);
				}else if(pos+3>=mm||a[pos+3]==2){
					search(res,a,mm,(now*3+2)*3+1,pos+2);
					search(res,a,mm,(now*9+1)*3+2,pos+3);
					search(res,a,mm,((now*3+1)*3+2)*3+1,pos+3);
				}
			}
			
		}else{
			search(res,a,mm,now*3,pos+1);
			search(res,a,mm,now*3+2,pos+1);
		}
	}
}
bool check(int x,int mm){
	int a[MAXN];
	for(int i=0;i<mm;++i){a[i]=x%3;x/=3;}
	for(int i=0;i<mm;++i)
		if(a[i]==1&&(!i||a[i-1]!=2)&&(i==mm-1||a[i+1]!=2))
			return false;
	return true;
}
int a[MAXN];
void solve(vector<node> query,int mm){
	int qsize=query.size();
	if(!qsize) return;
	sort(query.begin(),query.end());
	tot=0;
	dfs(0,0,mm);
	for(int i=0;i<tot;++i){
		num2[i]=get2(sta[i]);
		num0[i]=get0(sta[i],mm);
		nxt[i].clear();
		int ts=sta[i];
		for(int j=mm-1;j>=0;--j){
			a[j]=ts%3;
			ts/=3;
		}search(nxt[i],a,mm,0,0);
	}memset(dp,-1,sizeof(dp));
	for(int i=0;i<tot;++i)
		if(check(sta[i],mm))
			dp[1][i]=num2[i];
	int qid=0;
	for(int i=1;i<=MAXX-5;++i){
		while(qid<qsize&&query[qid].first==i){
			int qin=query[qid].second;
			ans[qin]=i*mm;
			sol[qin].clear();
			int tmp=-1;
			for(int j=0;j<tot;++j)
				if(dp[i][j]!=-1&&ans[qin]>dp[i][j]+num0[j]){
					tmp=j;
					ans[qin]=dp[i][j]+num0[j];
				}
			sol[qin].push_back(sta[tmp]);
			for(int j=i;j>1;j--){
				tmp=pre[j][tmp];
				sol[qin].push_back(sta[tmp]);
			}qid++;
		}if(qid==qsize) break;
		for(int j=0;j<tot;++j){
			if(dp[i][j]==-1) continue;
			for(int k=0;k<nxt[j].size();++k){
				int v=nxt[j][k];
				int idd=id[v];
				if(dp[i+1][idd]==-1||dp[i+1][idd]>dp[i][j]+num2[idd]){
					dp[i+1][idd]=dp[i][j]+num2[idd];
					pre[i+1][idd]=j;
				}
			}
		}
	}
}void print(vector<int> tor,int mm){
	for(int i=tor.size()-1;i>=0;--i){
		int v=tor[i];
		for(int j=0;j<mm;++j){
			if(v%3==2||(!i&&v%3==0)) printf("*");
			else printf(".");
			v/=3;
		}puts("");
	}
}int main(){
	for(int i=1;i<MAXM;++i)
		vec[i].clear();
	scanf("%d",&t);
	for(int i=0;i<t;++i){
		scanf("%d%d",&n,&m);
		vec[m].push_back(node(n,i));
		qm[i]=m;
	}for(int i=1;i<MAXM;++i)
		solve(vec[i],i);
	for(int Case=0;Case<t;++Case){
		printf("Case #%d: %d\n",Case+1,ans[Case]);
		print(sol[Case],qm[Case]);
	}
}

猜你喜欢

转载自blog.csdn.net/s260127ljy/article/details/107809621
今日推荐