紫书第七章暴力习题集

暴力破解# 系列文章目录

A . Division

暴力跑模拟分母

#define inf 0x3f3f3f3f
#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n=1;
	while(scanf("%d",&n)!=EOF&&n)
	{
		int i,b,c=1233;
		int flag=1;
		char x[99];
		while(c++)
		{
			b=c*n;
		    sprintf(x,"%05d%05d",b,c);
		    if(strlen(x)>10) break;
		    int s[12];
		    memset(s,0,sizeof(s));
		    for(i=0;i<10;i++)
		     {
				if(s[x[i]-'0']!=0) break;
		        else s[x[i]-'0']++;
			}
		    if(i==10) {printf("%05d / %05d = %d\n",b,c,n); flag=0;}
		}
		if(flag) printf("There are no solutions for %d.\n",n);
		printf("\n");
	}
	return 0;

}

}

B . Maximum Product

纯暴力跑,
我三个循环一点也没优化…

#include<bits/stdc++.h>
using namespace std;
int  a[30];
typedef long long ll
int main()
{
    int n,kss= 1;
    while(cin>>n){
        long long maxx = 1,m = -123456;
        memset(a,0,sizeof(a));
        for(int i = 0;i < n;i++)
            cin>>a[i];
        for(int i = 0;i < n;i++){
            for(int j = i;j < n;j++){
                for(int k = i;k <= j;k++){
                    maxx *= a[k];
                }
                if(maxx > m) m = maxx;
                maxx = 1;
            }
        }
           cout<<"Case #"<<kss++<<": The maximum product is ";
        if(m <= 0) cout<<0<<"."<<endl;
            else
            cout<<m<<"."<<endl;
        cout<<endl;
    }
    return 0;
}

C . Fractions Again?!

最难的就是找到模拟的范围
因为两个数相等时取最大值
所以(1/k)=(2/y)所以
从k+1模拟到2k
x=(y
k)/(y-k)

#include<bits/stdc++.h>
using namespace std;
const  int maxn=1e4+5; 
int a[maxn];
int b[maxn];
int main()
{
	int n,i,x,num;

    while(cin>>n)
    {
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        num=0;
        for(i=n+1; i<=n*2; i++)
        {
            if(n*i%(i-n)) 
			continue;
            x=n*i/(i-n);
            a[num]=x;
            b[num]=i;
            num++;
        }
        printf("%d\n",num);
        for(i=0; i<num; i++)
        printf("1/%d = 1/%d + 1/%d\n",n,a[i],b[i]);
    }
	return 0;
}

D . Prime Ring Problem

DFS
跑到(第一个数和第二个数(最大的)和是素数为止)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
int s[maxn];
ll n;
int a[20],vis[20];
bool su(int n)
{
    if(n<2)return false;
    for(int i=2;i*i<=n;i++)
    {
        if(n%i==0)
        {
            return false;
        }
    }
    return true;
}

void dfs(int x)
{
    if(x==n&&su(a[1]+a[n]))//终止条件 
    {
        for(int i=1;i<n;i++)
        {
            printf("%d ",a[i]);
        }
          printf("%d\n",a[n]);
    }
    else
    {
        for(int i=2;i<=n;i++)
        {
            if(!vis[i]&&su(i+a[x]))
            {
                a[x+1]=i;
                vis[i]=1;
                dfs(x+1);
                vis[i]=0; 
            }
        }
    }
}

int main()
{
    int flag=0;
    while(scanf("%d",&n)!=EOF)
    {
        memset(vis,0,sizeof(vis));
        a[1]=1;
      if(flag)
      cout<<endl;
      flag++;
        printf("Case %d:\n",flag);
        dfs(1);
    }
    return 0;
}

E . Krypton Factor

dfs

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+5;
int n, l;
int a[maxn];
bool f(int x)//判断是不是困难串 
{
	if(x == 1)
	return 1;
		bool flag;
	for(int i=1;i<=x/2;i++)
	{
		flag=1;
		for(int j=x-2*i;j<x-i; j++)
			if(a[j] != a[j + i])
				flag = 0;
		if(flag)
			 	return 0;
	}
	return 1;
}
 
void dfs(int x)
{
	if(n == 0)
	{
		for(int i = 0; i<x; i += 4)
		{
			if(i != 0 && i % (64) == 0)
				cout<<endl;
			else if(i)
				cout << " ";
			for(int j = 0; j < 4 && i + j < x; j++)
			     	putchar('A' + a[i + j]);
		}
		cout<<endl;
		cout <<x<<endl;
	}
	for(int i=0;i<l&&n; i++)
	{
		a[x] =i;
		if(f(x+1))//递归条件 
		{
			n--;
			dfs(x + 1);
		}
	}
}
 
int main()
{
	while(cin >> n >> l)
	{
	    memset(a, -1, sizeof(a)); 
		if(n==0&&l==0)
		{
			return  0;
		}
		
		dfs(0);
	}
	return 0;
}



F . Bandwidth

这是一个图,输入给出的是某个节点。冒号后面的是和这个节点相邻的节点有哪些 分号代表一个描述结束;
每一种排法中,相邻点距离最大的,作为这种排法的带宽。 问哪种排法带宽最小;
求最小宽度 用全排列即可

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int maxn=2e5+100;
vector<int> v[26];
bool ch[26]; 
int ans[10],id[10];


int main(){
	string line;
	while(cin>>line && line[0]!='#'){
		for(int i=0;i<26;i++) v[i].clear();
		memset(ch,0,sizeof(ch));
		for(int i=0,j,len=line.length();i<len;i++){
			ch[line[i]-'A']=true;
			for(j=i+2;j<len && line[j]!=';';j++){
				v[line[i]-'A'].push_back(line[j]-'A');
				ch[line[j]-'A']=true;
			}
			i=j;
		}

	int n=0;
		for(int i=0;i<26;i++) if(ch[i]) id[n++]=i;
		int res=n;
		do{
			int maxn=0;
			for(int i=0;i<n;i++){
				for(int j=0,len=v[id[i]].size();j<len;j++){
					for(int k=0;k<n;k++){
						if(id[k]==v[id[i]][j]) {
							maxn=max(maxn,abs(k-i));							
							break;
						}
					}
					if(maxn>=res) break;
				}
				if(maxn>=res) break;
			}
			if(res>maxn){
				memcpy(ans,id,sizeof(id));
				res=maxn;
			}
		}while(next_permutation(id,id+n));
		for(int i=0;i<n;i++)
			cout<<char(ans[i]+'A')<<" ";					
		cout<<"-> "<<res<<endl;
	}
	return 0;
}
————————————————
版权声明:本文为CSDN博主「牛郎恋刘娘,刘娘念牛郎」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_52172364/article/details/119033291
武子哥yyds

G . Mobile Computing

#include<bits/stdc++.h>
using namespace std;
struct Tree {
  double L, R;
  Tree():L(0),R(0) {}
}tree[1<<6];
int n, vis[1<<6];
double r, w[1<<6];
int cur;
double mmax;
 
void dfs(int d)
{
    if(d==n-1){
        if(tree[cur].L+tree[cur].R<=r){
            mmax=max(mmax,tree[cur].L+tree[cur].R);
            return;
        }
    }
    for(int i=1;i<=cur;i++){
        if(!vis[i]){
            for(int j=1;j<=cur;j++){
                if(!vis[j]&&i!=j){
                    vis[i]=vis[j]=1;
                    w[++cur]=w[i]+w[j];
                    int ll=w[i],rr=w[j];
                    double wl=rr*(1.0)/(ll+rr),wr=1-wl;
                    tree[cur].L=max(tree[i].L+wl,tree[j].L-wr);
                    tree[cur].R=max(tree[j].R+wr,tree[i].R-wl);
                    dfs(d+1);
                    vis[i]=vis[j]=vis[cur]=0;
                    tree[cur].L=tree[cur].R=0;
                    cur--;
                }
            }
        }
    }
}
 
int main()
{
    int T;
    cin>>T;
    while(T--){
        cur=0;
        memset(tree,0,sizeof(tree));
        memset(w,0,sizeof(w));
        scanf("%lf%d",&r,&n);
        for(int i=1;i<=n;i++){
            scanf("%lf",&w[i]);
            cur++;
        }
        mmax=-1;
        memset(vis,0,sizeof(vis));
        dfs(0);
        if(mmax==-1)cout<<mmax<<endl;
        else printf("%.16lf\n",mmax);
    }
    return 0;
}
 

H . Fill

武子哥yyds
T组测试数据,每组测试数据输入4个整数,分别表示第一个杯子的容量、第二个杯子的容量、第三个杯子的量、目标容量,4个整数(小于200大于0)。输出最小的总倒水量和目标容量,如果倒不出目标容量,就 输出能倒出的小于目标容量的最大的容量的总倒水量和容量。
a->b a->c b->a b->c c->a c->b 有这几种情况
桶是没有刻度的 只有容量大小

我们优先提取出 倒水过程中用量最少的 因为这样是最优的

#include<bits/stdc++.h>
#include<iostream>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f
//2147483647
using namespace std;
typedef long long ll;

typedef pair<double, double> PII;
ll n,m,k;
ll cnt=0,sum=0;
ll mod=1e9+7;
const int maxn=1e6+199;
ll x,y;	
int cap[3];
int vis[250][250];
int ans[250];

struct Node{
	int v[3];
	int dis;
	bool operator <(const Node& res) const{
		return res.dis<dis;
	}
}f,t;
void __init__(const Node & u){
	for(int i=0;i<3;i++){
		int k=u.v[i];
		if(ans[k]<0||ans[k]>u.dis) ans[k]=u.dis;
	}
}
void bfs(int a,int b,int c,int d){
	memset(vis,0,sizeof(vis));
	memset(cap,0,sizeof(cap));
	memset(ans,-1,sizeof(ans));
	cap[0]=a;cap[1]=b;cap[2]=c; //桶的容量
	priority_queue<Node>q;
	f.v[0]=0;
	f.v[1]=0;
	f.v[2]=c;
	f.dis=0;
	vis[0][0]=1;
	q.push(f);
	
	while(q.size()){
		f=q.top();   //提取出dis最小的  dis代表 倒水使用量
		q.pop();
		__init__(f);
		if(ans[d]>=0) break; //如果这个水量已经达到 直接break;
		
		for(int i=0;i<3;i++){
			for(int j=0;j<3;j++){
				if(i==j) continue;
				if(f.v[i]==0||f.v[j]==cap[j]) continue;
				
				int tmp=min(cap[j],f.v[i]+f.v[j])-f.v[j];  //tmp 代表j桶可以接收多少体积
				t=f;
				t.v[i]=f.v[i]-tmp;
				t.v[j]=f.v[j]+tmp;
				t.dis=f.dis+tmp;
				if(!vis[t.v[0]][t.v[1]]) //如果这个状态未曾有过 入队
				{
					vis[t.v[0]][t.v[1]]=1;
					q.push(t);
					
				}
			}
		}
	}
	
	while(d>=0){
		if(ans[d]>=0) {
				
				printf("%d %d\n",ans[d],d);
				return;
			}	
		
		d--;
	}
	
}

int main(){
	cin>>n;
	while(n--){
		int a,b,c,d;
		cin>>a>>b>>c>>d;
		bfs(a,b,c,d);
	}
}

I . The Morning after Halloween

BFS,题目大意是让最多三个鬼回到一模一样的大写字母那,tnl

#incldue<bits/stdc++.h>
using namespace std;
 
int bfs();
bool conflict(int a, int b, int na, int nb);
int encoding(int a, int b, int c);
 
const int MAXN = 150;
const int MAXS = 20;
const int dx[] = { 1,-1,0,0,0 };
const int dy[] = { 0,0,1,-1,0 };
 
int s[3], t[3];//保存初末状态  
int deg[MAXN], G[MAXN][5];//deg:某个格子有多少个相连的格子 ,G:存某个格子可以用到哪些格子  
int d[MAXN][MAXN][MAXN];	//走到某个状态经过的步数
 
int main()
{

	int w, h, n;
	while (scanf("%d %d %d", &w, &h, &n) && n) {
		getchar();
		char maze[MAXS][MAXS];
		for (int i = 0; i < h; i++) 
			fgets(maze[i], 20, stdin);//听说直接scanf会超时
		//为之后转化为一维数组做准备
		int cnt = 0, x[MAXN], y[MAXN], id[MAXN][MAXN];//cnt:非过道个数;x,y数组用来存储第cnt个过道的x,y值;
		for (int i = 0; i < h; i++) {				//id是来存储过道某个对应的cnt值
			for (int j = 0; j < w; j++) {
				if (maze[i][j] != '#') {
					if (islower(maze[i][j]))
						s[maze[i][j] - 'a'] = cnt;
					if (isupper(maze[i][j])) 
						t[maze[i][j] - 'A'] = cnt;
					x[cnt] = i; y[cnt] = j; id[i][j] = cnt++;
 				}
			}
		}
		//初始化deg,G。deg:每个过道5个移动方式上与之相邻的过道个数
		for (int i = 0; i < cnt; i++) {
			deg[i] = 0;
			for (int dir = 0; dir < 5; dir++) {
				int newx = x[i] + dx[dir];	int newy = y[i] + dy[dir];
				if (maze[newx][newy] != '#') G[i][deg[i]++] = id[newx][newy];
			}
		}
		//如果鬼的个数不足3个,补成三个,方便在BFS中进行对每个鬼进行行动,从而不需要动态考虑
		//并且在deg和G中开辟一个过道来存放该添加的鬼的始末位置。
		if (n <= 2) {
			deg[cnt] = 1; G[cnt][0] = cnt; s[2] = t[2] = cnt++;
		}
		if (n <= 1) {
			deg[cnt] = 1; G[cnt][0] = cnt; s[1] = t[1] = cnt++;
		}
		printf("%d\n", bfs());
	}
	return 0;
}
 
int bfs()
{
	queue<int> q;
	memset(d, -1, sizeof(d));
	d[s[0]][s[1]][s[2]] = 0;
	q.push(encoding(s[0], s[1], s[2]));//进行编码,放进栈中 
	while (q.size()) {
		int x = q.front(); q.pop();
		int a = (x >> 16) & 0xff, b = (x >> 8) & 0xff, c = x & 0xff;//获取abc
		if (a == t[0] && b == t[1] && c == t[2]) return d[a][b][c];//到达终点
		for (int i = 0; i < deg[a]; i++) {//a能移动的位置
			int na = G[a][i];
			for (int j = 0; j < deg[b]; j++) {
				int nb = G[b][j];
				if (conflict(a, b, na, nb)) continue;//如果冲突:a,b移动到同一个位置  或者  a,b交换位置
				for (int k = 0; k < deg[c]; k++) {
					int nc = G[c][k];
					if (conflict(a, c, na, nc))continue;
					if (conflict(b, c, nb, nc))continue;
					if (d[na][nb][nc] != -1)continue;//d有值说明该状态已经访问过
					d[na][nb][nc] = d[a][b][c] + 1;
					q.push(encoding(na, nb, nc));
				}
			}
		}
	}
}
 
bool conflict(int a, int b, int na, int nb)
{
	return (na == nb) || (na == b && nb == a);
}
 
int encoding(int a, int b, int c)
{
	return a << 16 | b << 8 | c;
}


J . Editing a Book

迭代加深法
题目大意:将一个数字序列以最少的剪切次数粘贴成另一个数字序列。
剪枝策略判断:当前估价函数值+当前深度>预先最大搜索深度 然后剪枝
剪枝最多改变三个数字位置的正确性
每次搜索前h>(maxd-d)*3时剪枝 (maxd-d)是剩余搜索次数

#include<bitsdc++.h> 
using namespace std;
const int maxn = 9;
int n, a[maxn];
bool is_finish() {
  for(int i = 0; i < n-1; i++)
    if(a[i] >= a[i+1]) return false;
  return true;
}// 判断是否到达目标状态
int h() {
  int cnt = 0;
  for(int i = 0; i <n-1; i++)
    if(a[i]+1 != a[i+1]) cnt++;
  if(a[n-1] != n) cnt++;
  return cnt;
} //统计需要变更的总数
bool dfs(int d, int maxd) {
  if(d*3 + h() > maxd*3) return false; //估价函数
  if(is_finish()) return true; //边界条件 
 
  int b[maxn], former[maxn];
  memcpy(former, a, sizeof(a)); //存放原图
  for(int i = 0; i < n; i++)
   for(int j = i; j < n; j++) {
     int cnt = 0;
     for(int k = 0; k < n; k++)
       if(k < i || k > j) b[cnt++] = a[k];
     for(int k = 0; k <= cnt; k++) {
       int cnt2 = 0;
       for(int p = 0; p < k; p++) a[cnt2++] = b[p]; //插入已经拍好序的
       for(int p = i; p <= j; p++) a[cnt2++] = former[p]; //插入
       for(int p = k; p < cnt; p++) a[cnt2++] = b[p]; //插入终止状态
 
       if(dfs(d+1, maxd)) return true;
       memcpy(a,former, sizeof(a));
     }
   }
  return false;
}
int solve() {
  if(is_finish()) return 0;
  int ans = 8;
  for(int maxd = 1; maxd <ans; maxd++)
    if(dfs(0, maxd)) return maxd;
  return ans;
}
int main() {
  int kass= 0;
  while(cin>>n&&n) {
    for(int i = 0; i < n; i++) scanf("%d", &a[i]);
    printf("Case %d: %d\n", ++kass, solve());
  }
  return 0;
}

K . Zombie’s Treasure Chest

一开始以为背包问题后来一看范围,那没事了
那就是数学问题,这时候考虑性价比了
取s2件物品1跟取s1件物品2体积一样
然后比较价值
拿(s1*s2)体积取,只能得到某一种物品
然后开始暴力维护最大值得到结果

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
    int k,t=0;
    scanf("%d",&k);
    while(k--){
        ll n,s1,s2,v1,v2,x,sum=0;
        cin>>n>>s1>>v1>>s2>>v2;
        ll s=s1*s2;
        v=max(s2*v1,s1*v2); 
       
	    x=n/s*v;//预处理的价值
        n%=s;
        
        if(s1<s2) swap(s1,s2),swap(v1,v2);
        for(ll i=0;i<=n/s1;++i){
             ll ans=0,m=n;
               ans+=i*v1;
               m-=i*s1;
             ans+=m/s2*v2;
             sum=max(sum,ans);
        }
        
        sum+=x;
        printf("Case #%d: %lld\n",++t,sum);
    }
    return 0;
}

L . Power Calculus

题目大意:
给定一个数n,让你求从1至少要做多少次乘除才可以从 x 得到 x^n。

跟j一样都差不多是迭代加深算法,也就是剪枝,估价函数
叫IDDFS
估价函数是当前值 << (还剩下的搜索层数)< n

#include<bits/stdc++.h>
using namespace std;

int val[1010]={0};
int pos,d;
int n;
bool dfs(int now)
{
	if(now>d) return false;
	if(val[pos]<<(d-now)<n)
	 return false;//估价函数 
	if(val[pos]==n) 
	return true;//搜索结束
	 
	pos++;
	for(int i=0;i<pos;i++)
	{
		val[pos]=val[pos-1]+val[i];
		if(dfs(now+1)) return true;
		val[pos]=fabs(val[pos-1]-val[i]);
		if(dfs(now+1)) return true;
	}
	pos--;//重置 
	return false;
}
int main()
{
	while(cin>>n&&n!=0)
	{
		d=0;
		while(true)
		{
			val[0]=1;
			pos=0;
			if(dfs(0)) break;
			d++;
		}
		cout<<d<<endl;
	}
	return 0;
}

M . Lattice Animals


#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <set>
#define INF 0x3f3f3f
 
using namespace std;
 
const int dx[] = {-1, 1, 0, 0};//方向数组
const int dy[] = {0, 0, -1, 1};
int n, w, h;
int ans[15][15][15];//所有输入对应的答案
struct cell//定义单元格
{
    int x, y;
    cell(int a, int b)
    {
        x = a;
        y = b;
    }
    cell(){}
    bool operator <(const cell &rhs) const
    {
        if (x != rhs.x) return x < rhs.x;
        return y < rhs.y;
    }
};
typedef set<cell> poly;//n个坐标的集合也就是一个n连块
set<poly> vis[15];//用来判重的set,vis[n]是被访问过的所有n连块的集合
 
poly initial_normal(const poly &p)//将这个n连块标准化成左上角在(0,0)点
{
    poly goal;
    int minx = INF, miny = INF;
    for (cell it : p)
    {
        minx = min(minx, it.x);
        miny = min(miny, it.y);
    }
    for (cell it : p)
        goal.insert((cell){it.x - minx, it.y - miny});
    return goal;
}
 
inline poly rotate(const poly &p)//顺时针旋转转90°,千万记住末尾返回的应该是标准化之后的答案
{                                //因为有的n连块顺时针旋转90°之后出界了,需要将其标准化。
    poly goal;                  //因为这个函数会被执行多次,用inline可以加快执行速度
    for(poly::iterator i=p.begin(); i!=p.end(); i++)
        goal.insert(cell(i->y, -i->x));
    return initial_normal(goal);
}
 
inline poly flip(const poly &p)//将一个n连块沿x轴翻转,同时也要将答案标准化
{
    poly goal;
    for(poly::iterator i=p.begin(); i!=p.end(); i++)
        goal.insert(cell(i->x,-i->y));
    return initial_normal(goal);
}
 
bool had_vis(poly p)//判断一个n连块是否访问过,没访问过就插入到vis里面,返回false
{
    int len = p.size();
    for (int i=0; i<4; i++)
    {
        p = rotate(p);
        if (vis[len].count(p))
            return true;
    }
    p = flip(p);//将p翻转之后,再次顺时针旋转看出现过没有
    for (int i=0; i<4; i++)
    {
        p = rotate(p);
        if (vis[len].count(p))
            return true;
    }
    vis[len].insert(p);
    return false;
}
 
void dfs(const poly &p)//由当前k连块dfs到n连块
{
    if (p.size() == n)
    {
        had_vis(p);
        return;
    }
    for (cell cur : p)
    {
        for (int d=0; d<4; d++)
        {
            cell next(cur.x + dx[d], cur.y + dy[d]);
            //if(next.x >= 0 && next.x < w && next.y >= 0 && next.y < h && !p.count(next))
            //刚开始这里是这样写的,最后答案错误,想了很久才发现。现在的目标不是dfs出
            //一个可以装进w*h网格中的n连块,现在的目的是dfs出所有的n连块,所以不在乎能不能装进去
            if (!p.count(next))
            {
                poly p_next = p;
                p_next.insert(next);
                dfs(p_next);
            }
        }
    }
}
 
void print_table()//将所有可能的输入打表
{
    memset(ans, 0, sizeof(ans));
    poly S;
    S.insert(cell(0, 0));//得到1连块
    vis[1].insert(S);
    for (n=2; n<=10; n++)//首先搜索n = 10的情况,这样搜索一遍后,vis里面
    {                   //就含有了所有大小的连通块。搜索k连块是借用的k-1连块的搜索结果。
        for (poly it1 : vis[n - 1])
            dfs(it1);
    }
    for (n=2; n<=10; n++)//对所有可能打表
        for (w=1; w<=10; w++)
            for (h=1; h<=10; h++)
        {
            int cnt=0;
            for (poly it1 : vis[n])
            {
                int maxx=0,maxy=0;
                for (cell it2 : it1)//寻找当前的连通块的最大的x,y
                {
                    maxx = max(maxx, it2.x);
                    maxy = max(maxy, it2.y);
                }
                //能够放入w*h网格内的条件
                if(min(maxx, maxy) < min(h, w) && max(maxx, maxy) < max(h, w))
                    cnt++;
            }
            ans[n][w][h]=cnt;
        }
}
 
int main()
{
    print_table();
    while (scanf("%d%d%d", &n, &w, &h)==3)
    {
        if (n == 1) {printf("1\n");continue;}//1的时候特判
        printf("%d\n", ans[n][w][h]);
    }
    return 0;
}

N . Square Destroyer

#include<bits/stdc++.h>
int n,m,maxd,cnt,sum;
int FullSize[625],Size[625];
bool sti[65],in[625][65];
inline int getc(int r,int c)// |  竖线
{
    return r*(2*n+1)+c+n+1;
}
inline int getr(int r,int c)//--   横线
{
    return r*(2*n+1)+c+1;
}
inline int FindNext()//找到下一个没有破坏的正方形
{
    for(int i=1;i<=cnt;i++)
        if(Size[i]==FullSize[i])
            return i;
    return 0;
}
void dfs(int d)//深搜
{
    if(d>=maxd) return;//最优性剪枝
    int next=FindNext();
    if(next==0)
    {
        maxd=d;
        return;
    }
    for(int i=1;i<=sum;i++)
        if(in[next][i])
        {
            for(int j=1;j<=cnt;j++)//删掉火柴棍
                if(in[j][i]) Size[j]--;
            dfs(d+1);
            for(int j=1;j<=cnt;j++)//复原
                if(in[j][i]) Size[j]++;
        }
}
int main()
{
#ifdef local
    freopen("pro.in","r",stdin);
#endif
    int kase;
    scanf("%d",&kase);
    while(kase-->0)
    {
        memset(in,0,sizeof(in));
        memset(sti,1,sizeof(sti));
        cnt=0;
        scanf("%d%d",&n,&m);
        int a,b,e,f;
        for(int i=0;i<m;i++)
        {
            scanf("%d",&a);
            sti[a]=0;
        }
        //状态压缩+预处理
        for(int len=1;len<=n;len++)
            for(int r=0;r+len<=n;r++)
                for(int c=0;c+len<=n;c++)
                {
                    cnt++;
                    FullSize[cnt]=len*4;
                    Size[cnt]=0;
                    for(int i=0;i<len;i++)
                    {
                        a=getr(r,c+i);
                        b=getr(r+len,c+i);
                        e=getc(r+i,c);
                        f=getc(r+i,c+len);
                        in[cnt][a]=true;
                        in[cnt][b]=true;
                        in[cnt][e]=true;
                        in[cnt][f]=true;
                        Size[cnt]+=sti[a]+sti[b]+sti[e]+sti[f];
                    }
                }
        maxd=n*n;//设置上限
        sum=2*n*(n+1);
        dfs(0);
        printf("%d\n",maxd);
    }
    return 0;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值