D-小心火烛的歪

思路: DFS求序列的组合问题,就是一个序列 1 ~ q,从序列里选一个数有哪些选法,选两个数有哪些选法,选三个数有哪些选法...(不考虑顺序)

选好了数之后就检查是否满足条件,怎么检查呢?

用一个二维数组存储选了的这些方案的最终结果,然后与原图进行比较,如果对于每一位异或结果都为 1,说明放杂物的地方不会放烟花,没有放杂物的地方一定会放烟花;如果异或结果是 0,那就不满足题意,直接退出,去找下一种方案

相似题目:医生

具体思路请看代码:

//		https://ac.nowcoder.com/acm/contest/96115/D


#include <bits/stdc++.h>
using namespace std;
#define endl "\n"

int n,m,q;
int vis[10];
int d[10];//记录选了哪些方案
bool sign;//是否满足条件,这个标记变量贯穿始终
vector<string> a(10);
void check(vector<vector<string>>& v, int k)
{
	vector<vector<int>> temp(n,vector<int>(m,0));//存所有方案得出的结果
	for(int i=0;i<k;i++)//选的方案
		for(int j=0;j<n;j++)//第i种方案的行
			for(int p=0;p<m;p++)//列
				temp[j][p] |= v[d[i]][j][p]-'0';//或运算,计算所有方案得出的结果
	sign=1;
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<m;j++)
		{
			if(((a[i][j]-'0') ^ temp[i][j]) != 1)//异或结果不为1,说明有杂物的地方会放烟花 或者 没有放杂物的地方却没有放烟花
			{
				sign=0;
				break;
			}
		}
	}
}

void dfs(vector<vector<string>>& v, int index, int x, int k)//index为当前下标,x为选了多少个方案,k为要选多少个方案
{
	if(x==k)
	{
		check(v,k);//检查是否满足条件
		if(sign)
		{
			cout<<k<<endl;
			for(int i=0;i<k;i++)
				cout<<d[i]+1<<" ";
			cout<<endl;
			return ;
		}
		return ;
	}
	for(int i=index+1;i<q;i++)
	{
		if(vis[i]==0)
		{
			vis[i]=1;
			d[x]=i;
			dfs(v,i,x+1,k);
			if(sign)return ;
			vis[i]=0;
		}
	}
}
void solve(){
	cin>>n>>m>>q;
	for(int i=0;i<n;i++)cin>>a[i];
	vector<vector<string>> v(q,vector<string>(n));//类似三维字符数组
	for(int i=0;i<q;i++)
		for(int j=0;j<n;j++)
			cin>>v[i][j];
	//特判全1的情况,这种情况输出0而不是-1
	sign=1;
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<m;j++)
		{
			if(a[i][j]=='0')
			{
				sign=0;
				break;
			}
		}
		if(!sign)break;
	}
	if(sign)
	{
		cout<<0;
		return ;
	}
	for(int i=1;i<=q;i++)//选一种方案,选两种方案...... q 种方案全选,遍历
	{
		for(int j=0;j<q;j++)vis[j]=0;//初始化
		dfs(v,-1,0,i);
		if(sign)return;
	}
	cout<<-1<<endl;
}

signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int t;
	t=1;
	//cin>>t;
	while(t--)
		solve();
}