Living-Dream 系列笔记 第8期

Posted on 2024-03-09 12:29  _XOFqwq  阅读(13)  评论(0编辑  收藏  举报

本期主要讲解的与上期相同。

例题

T1

上课的时候调这个题感觉要吐了 \(qwq\)。。。

首先读入 \(n\) 行字符串,可以采取忽略中间无关单词的方式来直接读取 \(X\)\(Y\)

将所有名字存入 \(a\) 数组,对 \(a\) 数组按字典序排序后就可以开始 \(\text{DFS}\) 了,这里建议使用 next_premutation

设计一个 check 函数来判定当前全排列是否满足 \(n\) 条限制。具体实现:

  • 遍历 \(n\) 条限制,对于第 \(i\) 条限制,在 \(8\) 个名字中找到对应的 \(X_i\)\(Y_i\),保存它们的位置。

  • 判断它们位置的绝对差是否 \(=1\)(相邻)即可。

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

int n;
string x[8],y[8];
string ans[8]={"Beatrice","Belinda","Bella","Bessie","Betsy","Blue","Buttercup","Sue"};

int getpos(string x){
	int p;
	for(int i=0;i<8;i++)
		if(ans[i]==x){
			p=i; break;
		}
	return p;
}
bool check(){
	for(int i=1;i<=n;i++){
		int p1=getpos(x[i]),p2=getpos(y[i]);
		if(abs(p1-p2)!=1) return 0;
	}
	return 1;
}

int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>x[i];
		for(int j=1;j<=5;j++)
			cin>>y[i];
	}
	
	do{
		if(check()){
			for(int i=0;i<8;i++) cout<<ans[i]<<'\n';
			break;
		}
	}while(next_permutation(ans,ans+8));
	
	return 0;
}

习题

T2

一个矩阵有主对角线(左上到右下)和副对角线(右上到左下),主对角线经过点的 \(x,y\) 坐标差一定,副对角线则是和一定。

于是我们可以记录三个 \(bool\) 数组 \(c,m,e\),分别记录在当前列 / 主对角线 / 副对角线是否能放置皇后。

\(\text{dfs(x)}\) 中我们定义行为格子,列为填入的数字,那么此题就变成了一个全排列问题。在 \(1 \sim n\) 遍历填入哪一列时,我们仅需判断 \(c_i,m_{x-i+n},e_{x_i}\) 是否均为 \(false\),若是则可以放置皇后。

注意回溯。

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

int n,sum,ans[31];
int col[31],m[31],e[31];

void dfs(int x){
    if(x==n+1){
        sum++;
        if(sum<=3){
            for(int i=1;i<=n;i++) cout<<ans[i]<<' ';
            cout<<'\n';
        }
        return;
    }
    
    for(int i=1;i<=n;i++){
        if(!col[i]&&!m[x-i+n]&&!e[x+i]){
            col[i]=m[x-i+n]=e[x+i]=1;
            ans[x]=i;
            dfs(x+1);
            col[i]=m[x-i+n]=e[x+i]=0;
        }
    }
}

int main(){
    cin>>n;
    dfs(1);
    cout<<sum;
    return 0;
}

T3

考虑指数型枚举,即填格子时仅有填 / 不填两种选择,时间复杂度 \(O(2^n)\)

\(\text{DFS}\) 函数中传入两个参数:\(x\)\(tot\),分别记录即将填的格子数以及已经填完的格子数。

\(x=g+1\) 时,若符合要求且 \(tot <\) 全局答案,则更新全局答案并将当前选择方案 \(copy\) 给全局选择方案。

对于判断某一方案是否合法,则可以对于所有选择的种类,依次判断每一列之和是否 \(<\) 每头牛需要的维他命,若是则返回 \(1\);若均 \(\ge\) 所需维他命,则返回 \(1\)

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

int v,g,minn=1e9+31;
int ans[31],Ans[31];
int a[31],b[31][31];

bool check(int tot){
    for(int j=1;j<=v;j++){
        int sum=0;
        for(int i=1;i<=tot;i++) sum+=b[ans[i]][j];
        if(sum<a[j]) return 0;
    }
    return 1;
}

void dfs(int x,int tot){
    if(x==g+1){
        if(check(tot)){
            if(tot<minn){
                minn=tot;
                for(int i=1;i<=minn;i++) Ans[i]=ans[i];
            }
        }
        return;
    }

    ans[tot+1]=x;
    dfs(x+1,tot+1);
    
    dfs(x+1,tot);
}

int main(){
    cin>>v;
    for(int i=1;i<=v;i++) cin>>a[i];
    cin>>g;
    for(int i=1;i<=g;i++)
        for(int j=1;j<=v;j++)
            cin>>b[i][j];
    dfs(1,0);

    cout<<minn<<' ';
    for(int i=1;i<=minn;i++) cout<<Ans[i]<<' ';
    return 0;
}

T4

建立一个 \(b\) 数组保存下标,对 \(b\) 数组进行枚举全排列来遍历所有的顺序。

对于每一种顺序,遍历 \(n\) 个点,通过对上 / 下 / 左 / 右 / 离它最近的油的边界与它的距离取 \(\min\) 来得到在第 \(i\) 个点的最大半径,累加所有 \(n\) 格点的半径,用总面积减去就得到了剩余面积,对所有这样的剩余面积取 \(\min\) 即可。

注意精度问题。

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

int n,ans=1e9+31;
double S,up,down,lft,rgt;
double x,y,xx,yy;
double rr[31];
struct node{
    int a,b;
}p[31];
int id[31];

double dist(int aa,int bb){
    return sqrt((p[aa].a-p[bb].a)*(p[aa].a-p[bb].a)+(p[aa].b-p[bb].b)*(p[aa].b-p[bb].b));
}
double surf(){
    double sum=0.0;
    for(int i=1;i<=n;i++){
        double u=up-p[id[i]].b,d=p[id[i]].b-down,l=p[id[i]].a-lft,r=rgt-p[id[i]].a;
        double t=1e9;
        for(int j=i-1;j>=1;j--)
            t=min(t,dist(id[i],id[j])-rr[j]);
        
        if(t<0){ rr[i]=0; continue; }
        rr[i]=min(u,min(d,min(l,min(r,t))));
        sum+=rr[i]*rr[i]*3.1415926;
    }
    return sum;
}

int main(){
    cin>>n;
    cin>>x>>y>>xx>>yy;
    for(int i=1;i<=n;i++){
        cin>>p[i].a>>p[i].b;
        id[i]=i;
    }
    up=max(y,yy),down=min(y,yy),lft=min(x,xx),rgt=max(x,xx);
    S=(up-down)*(rgt-lft);
    
    do{
        double sf=surf();
        ans=min(ans,(int)(round(S-sf)));
    }while(next_permutation(id+1,id+n+1));
    cout<<ans;
    return 0;
}