北化ACM集训队保金争银夺铜-第01周-003-Div2-基础搜索

文章目录

  • A.棋盘问题
  • B. Catch That Cow
  • C.Find The Multiple
  • D.Prime Path
  • E.Shuffle'm Up
  • F.Pots
  • G.迷宫问题
  • H. Oil Deposits
  • I.非常可乐
  • J.Find a way
  • K.Gap
  • L.Eight
  • M.Nightmare Ⅱ

A.棋盘问题

程序返回可行解的个数,最好使用dfs
因为每行只能放一个棋子,所以每一行的状态只需用一个数表示,记录棋子的位置
整个棋盘的状态用一个一维数组表示

#include
#include
#include
#include
using namespace std;
typedef long long ll;
int pos[10];
string h[10];
int n,k;
ll solve(int hang,int res_k){
    ll res=0;
    if(res_k==0) return 1;
    if(hang>=n) return 0;
    res+=solve(hang+1,res_k); 
    // cout<
    for( int i=0;i<n;i++){
        if(h[hang][i]=='.') continue;
        else {
            for( int j=0;j<hang;j++)
                if(pos[j]==i) goto endd;
            
            pos[hang]=i;
            res+=solve(hang+1,res_k-1);
            pos[hang]=-1;
            endd:;
        }
    }
    return res;
}
int main(){
    while(cin>>n>>k){
        // if(n==0||k==0) {
        //     cout<<0<
        //     continue;
        // }
        if(n==-1&&k==-1) break;
        for( int i=0;i<n;i++){
            cin>>h[i];
        }
        memset(pos,-1,sizeof(pos));
        cout<<solve(0,k)<<endl;        
    }    
    return 0;
}

B. Catch That Cow

直接写

#include
#include
#include

using namespace std;
const int N=110;
int a,b;
int vis[1000100];
int step[1000100];
int bfs(){
    queue<int>q;
    vis[a]=1;
    q.push(a);
    while(!q.empty()){
        int now=q.front();
        q.pop();
        if(now==b) break;
        if(now>5e5+2) continue;
        if(vis[now*2]==0){
            vis[now*2]=1;
            step[now*2]=step[now]+1;
            q.push(now*2);
        }
        if(now-1>=0&&vis[now-1]==0){
            vis[now-1]=1;
            step[now-1]=step[now]+1;
            q.push(now-1);
        }
        if(vis[now+1]==0){
            vis[now+1]=1;
            step[now+1]=step[now]+1;
            q.push(now+1);
        }
    }
    return step[b];
}
int main(){
    cin>>a>>b;
    cout<<bfs()<<endl;
    return 0;
}

C.Find The Multiple

用python写的,代码质量不太高

vis={-1};
def dfs(x):
    if(x in vis):
        return -1;
    vis.add(x);
    s=str(x);
    if(len(s)>100):
        return -1;
    if(x!=0 and x%n==0):
        return x;
    res=dfs(x*10);
    if(res!=-1) :
        return res;
    res=dfs(x*10+1);
    if(res!=-1):
        return res;
    return -1;
        
while(1):
    global n
    n=int(input());
    vis={-1}
    if(n==0):
        break;
    print(dfs(0));
    
    

D.Prime Path

先预处理出所有质数,然后处理出质数之间的状态转移路径。这和状压dp比较相似

#include 
#include
#include
#include
#include
#include
using namespace std;
const int N=100100;
vector<int>h[N];
int st[N];//1不是质数0是质数
void get_prime(){
    st[1]=1;
    for( int i=2;i<=9999;i++){
        if(st[i]!=0) continue;
        for( int j=i+i;j<=9999;j+=i){
            st[j]=1;
        }
    }
    return ;
}
string int_to_string(int x){
    string res;
    res+=x/1000+'0',x%=1000;
    res+=x/100+'0',x%=100;
    res+=x/10+'0',x%=10;
    res+=x+'0';
    return res;
}
int string_to_int(string s){
    int res=0;
    for( int i=0;i<s.size();i++){
        res=res*10+s[i]-'0';
    }
    return res;
}
void get_path(){
    for( int i=1000;i!=9999;i++){
        if(st[i]==1) continue;
        string s=int_to_string(i);
        for( int j=0;j<4;j++){
            string ss=s;
            for( int k=0;k<10;k++){
                if(j==0&&k==0) continue;
                ss[j]=k+'0';
                int x=string_to_int(ss);
                if(x==i) continue;
                if(st[x]==0) h[i].push_back(x);
            }
        }
    }
}
int be,en;
int bfs( ){
    if(be==en) return 0;
    queue<int>q;
    q.push(be);
    int vis[100100]={};
    int step[100100]={};
    memset(step,0x3f,sizeof(step));
    step[be]=0;
    while(!q.empty()){
        int now=q.front();
        q.pop();
        for( int i=0;i<h[now].size();i++){
            if(h[now][i]==en) return step[now]+1;
            if(vis[h[now][i]]==0){
                vis[h[now][i]]=1;
                q.push(h[now][i]);
                step[h[now][i]]=step[now]+1;
            }
        }
    }
    return -1;
}
int main(){
    int t;
    cin>>t;
    get_prime();
    get_path();
    while(t--){
        cin>>be>>en;
        int ans=bfs();
        if(ans==-1){
            cout<<"Impossible"<<endl;
        }
        else cout<<ans<<endl;
    }
    return 0;
}

E.Shuffle’m Up

直接模拟

#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
string s1,s2,s12;
int n;
int solve(){
    int res=0;
    string now;
    set<string>vis;
    while(now!=s12){
        if(vis.find(now)!=vis.end()) return -1;
        else vis.insert(now);
        // cout<
        now.clear();
        for( int i=0;i<n*2;i++){
            if(i%2==0) now+=s2[i/2];
            else now+=s1[i/2];
        }
        // cout<
        res++;
        
        s1.clear();
        s2.clear();
        for( int i=0;i<n;i++) {
            s1+=now[i];
        }
        for( int i=n;i<n+n;i++){
            s2+=now[i];
        }
    }
    return res;
}
int main(){
    int t;
    cin>>t;
    for( int tt=1;tt<=t;tt++){
        cin>>n>>s1>>s2>>s12;
        cout<<tt<<" "<<solve()<<endl;
    }
    return 0;
}

F.Pots

模拟倒水,用一个数组存储最优解的来源

#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N=110;
int step[N][N];
pair<int,int> pre[N][N];
int pre_val[N][N];
int a,b,c;
//1.fill1 2.fill2 3.drop1 4.drop2 5.pour1,2 6.pour2,1 
pair<int,int> change( pair<int,int>p,int x){
    if(x==1) {
        p.first=a;
        return p;
    }
    else if(x==2){
        p.second=b;
        return p;
    }
    else if(x==3){
        p.first=0;
        return p;
    }
    else if(x==4){
        p.second=0;
        return p;
    }
    else if(x==5){
        int mov=min(b-p.second,p.first);
        p.first-=mov;
        p.second+=mov;
        return p;
    }
    else if(x==6){
        int mov=min(a-p.first,p.second);
        p.second-=mov;
        p.first+=mov;
        return p;
    }
}
int bfs( int x,int y){
    set<pair<int,int> >vis;
    queue<pair<int,int> >q;
    q.push(make_pair(x,y));
    vis.insert(make_pair(x,y));
    while(!q.empty()){
        pair<int,int>now=q.front();
        q.pop();
        if(now.first==c||now.second==c){
            a=now.first,b=now.second;
            return step[now.first][now.second];
        } 
        for( int i=1;i<=6;i++){
            pair<int,int>temp=change(now,i);
            if(vis.find(temp)==vis.end()){
                step[temp.first][temp.second]=step[now.first][now.second]+1;
                vis.insert(temp);
                q.push(temp);
                pre[temp.first][temp.second]=make_pair(now.first,now.second);
                pre_val[temp.first][temp.second]=i;
            }
        }
    }
    return -1;
}
int main(){
    cin>>a>>b>>c;
    int ans=bfs(0,0);
    if(ans!=-1){
        cout<<ans<<endl;
        stack<int>st;
        while(a!=0||b!=0){
            st.push(pre_val[a][b]);
            int aa=pre[a][b].first;
            int bb=pre[a][b].second;
            a=aa,b=bb;
        }
        while(!st.empty()){
            int t=st.top();
            st.pop();
            if(t==1){
                cout<<"FILL(1)"<<'\n';
            }
            else if(t==2){
                cout<<"FILL(2)"<<'\n';
            }
            else if(t==3){
                cout<<"DROP(1)"<<'\n';
            }
            else if(t==4){
                cout<<"DROP(2)"<<'\n';
            }
            else if(t==5){
                cout<<"POUR(1,2)"<<'\n';
            }
            else if(t==6){
                cout<<"POUR(2,1)"<<'\n';
            }
        }
    }
    else cout<<"impossible"<<endl;
    return 0;
}

G.迷宫问题

直接写

#include
#include
#include
#include
#include
#include
using namespace std;
const int inf=0x3f3f3f3f,N=510;
int a[10][10],prex[10][10],prey[10][10],vis[10][10];
int mov[4][2]={0,1,0,-1,1,0,-1,0};
int check( pair<int,int> p){
    if(vis[p.first][p.second]==1) return 0;
    if(p.first<1||p.first>5||p.second<1||p.second>5||a[p.first][p.second]==1) return 0;
    return 1;
}
void bfs(){
    queue<pair<int,int> > q;
    q.push(make_pair(1,1));
    vis[1][1]=1;
    while(!q.empty()){
        pair<int,int> now=q.front();
        q.pop();
        // cout<
        if(now.first==5&&now.second==5) break;
        vis[now.first][now.second]=1;
        for( int i=0;i<4;i++){
            pair<int,int>temp=now;
            temp.first+=mov[i][0];
            temp.second+=mov[i][1];
            if(check(temp)){
                prex[temp.first][temp.second]=now.first;
                prey[temp.first][temp.second]=now.second;
                q.push(temp);
            }
        }

    }
}
int main(){
    int n=5;
    for( int i=1;i<=n;i++){
        for( int j=1;j<=n;j++){
            cin>>a[i][j];
        }
    }
    bfs();
    int x=5,y=5;
    stack<int >ansx;
    stack<int >ansy;
    while(1){
        ansx.push(x-1);
        ansy.push(y-1);
        int xx=prex[x][y];
        int yy=prey[x][y];
        x=xx,y=yy;
        if(x==1&&y==1) break;
    }
    ansx.push(0),ansy.push(0);
    while(!ansx.empty()){
        printf("(%d, %d)\n",ansx.top(),ansy.top());
        ansx.pop(),ansy.pop();
    }
    return 0;
}

H. Oil Deposits

#include 
#include
#include
#include
#include
#include
using namespace std;
const int N=110;
int n,m;
string h[N];
int vis[N][N];
int mov[8][2]={0,1,0,-1,1,0,1,1,1,-1,-1,-1,-1,0,-1,1};
int check(pair<int,int>p){
    if(p.first<0||p.first>=n||p.second<0||p.second>=m) return 0;
    if(h[p.first][p.second]=='*'||vis[p.first][p.second]==1) return 0;
    return 1;
    
}
void bfs( int x,int y){
    queue<pair<int,int> >q;
    q.push(make_pair(x,y));
    vis[x][y]=1;
    while(!q.empty()){
        pair<int,int>now=q.front();
        q.pop();
        for( int i=0;i<8;i++){
            pair<int,int>temp=now;
            temp.first+=mov[i][0];
            temp.second+=mov[i][1];
            if(check(temp)==1){
                vis[temp.first][temp.second]=1;
                q.push(temp);
            }
        }
    }
    
}
int main(){
    while(cin>>n>>m){
        if(n==0&&m==0) break;
        memset(vis,0,sizeof(vis));
        for( int i=0;i<n;i++){
            cin>>h[i];
        }
        int ans=0;
        for( int i=0;i<n;i++){
            for( int j=0;j<m;j++){
                if(vis[i][j]==0&&h[i][j]=='@'){
                    bfs(i,j);
                    ans++;
                }
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

I.非常可乐

写一个倒水函数可以减少代码量

#include 
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int vis[110][110][110];
int step[110][110][110];
int w[3];
struct p{
    int a[3];
};
p pour(int from,int to,p x){
    int mov=min(x.a[from],w[to]-x.a[to]);
    x.a[from]-=mov;
    x.a[to]+=mov;
    return x;
}
int check(p now){
    int cnt=0;
    for( int i=0;i<3;i++){
        if(now.a[i]*2==w[0]) cnt++;
    }
    if(cnt==2) return 1;
    else return 0;
}
int bfs( p be){
    queue<p>q;
    q.push(be);
    vis[be.a[0]][be.a[1]][be.a[2]]=1;
    while(!q.empty()){
        p now=q.front();
        q.pop();
        if(check(now)) return step[now.a[0]][now.a[1]][now.a[2]];
        for( int i=0;i<3;i++){
            for( int j=0;j<3;j++){
                if(i==j) continue;
                p temp=pour(i,j,now);
                if(vis[temp.a[0]][temp.a[1]][temp.a[2]]==0){
                    vis[temp.a[0]][temp.a[1]][temp.a[2]]=1;
                    step[temp.a[0]][temp.a[1]][temp.a[2]]=step[now.a[0]][now.a[1]][now.a[2]]+1;
                    q.push(temp);
                }
            }
        }
    }
    return -1;

}
int main(){
    while(cin>>w[0]>>w[1]>>w[2]){
        if(w[0]==0&&w[1]==0&&w[2]==0) break;
        memset(vis,0,sizeof(vis));
        memset(step,0,sizeof(step));
        p now;
        now.a[0]=w[0],now.a[1]=0,now.a[2]=0;
        int ans=bfs(now);
        if(ans==-1) cout<<"NO"<<endl;
        else cout<<ans<<endl;
    }    
    return 0;
}

J.Find a way

对M和Y分别进行bfs,用两个数组记录距离,然后遍历每个@的距离,取最小值

#include
#include
#include
#include
#include

using namespace std;
typedef long long ll;
const int N=210,inf=0x3f3f3f3f;
int n,m;
string h[N];
int vis[N][N];
int step[N][N][2];
int mov[4][2]={0,1,0,-1,1,0,-1,0};
int check(pair<int,int> p){
    if(p.first<0||p.first>=n||p.second<0||p.second>=m) return 0;
    if(vis[p.first][p.second]==1||h[p.first][p.second]=='#') return 0;
    return 1;
}
void bfs(int x,int y,int flag){
    memset(vis,0,sizeof(vis));
    queue<pair<int,int> >q;
    q.push(make_pair(x,y));
    vis[x][y]=1;
    while(!q.empty()){
        pair<int,int>now=q.front();
        q.pop();
        for( int i=0;i<4;i++){
            pair<int,int>temp=now;
            temp.first+=mov[i][0];
            temp.second+=mov[i][1];
            if(check(temp)){
                vis[temp.first][temp.second]=1;
                step[temp.first][temp.second][flag]=step[now.first][now.second][flag]+1;
                q.push(temp);
            }
        }
    }
}
int main(){
    while(cin>>n>>m){
        memset(step,0,sizeof(step));
        for( int i=0;i<n;i++){
            cin>>h[i];
            for( int j=0;j<m;j++){
                if(h[i][j]=='@'){
                    step[i][j][0]=step[i][j][1]=inf;
                }
            }
        }
        for( int i=0;i<n;i++){
            for( int j=0;j<m;j++){
                if(h[i][j]=='Y'){
                    bfs(i,j,0);
                }
                if(h[i][j]=='M'){
                    bfs(i,j,1);
                }
            }
        }
        int ans=inf;
        for( int i=0;i<n;i++){
            for( int j=0;j<m;j++){
                if(h[i][j]=='@'){
                    ans=min(step[i][j][0]+step[i][j][1],ans);
                }
            }
        }
        cout<<ans*11<<endl;
    }
    return 0;
}

K.Gap

本题需要对每个状态进行状态压缩,压缩的方法是将两位数当成一个字符,存在一个string中,判重数组直接用set代替

#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
#define x first
#define y second
#define hash hashh
const int N=110;
int w[10][10];
int now[10][10];
string ans_s;
string hash(){
    string res;
    for( int i=0;i<4;i++){
        for( int j=0;j<=7;j++){
            res+=now[i][j];
        }
    }
    return res;
}
void rehash(string &s){
    memset(now,0,sizeof(now));
    for( int i=0;i<4;i++){
        for( int j=0;j<=7;j++){
            now[i][j]=s[i*8+j];
        }
    }
}
pair<int,int> find(int a){
    for( int i=0;i<4;i++){
        for( int j=0;j<=7;j++){
            if(now[i][j]==a){
                return make_pair(i,j);
            }
        }
    }
    return make_pair(-1,-1);
}
void debugg(){
    for( int i=0;i<4;i++){
        for( int j=0;j<=7;j++){
            cout<<now[i][j]<<" ";
        }
        cout<<endl;
    }
    cout<<endl<<endl;
}
void init(){
    for( int i=0;i<4;i++){
        for( int j=0;j<=7;j++){
            now[i][j]=w[i][j];
        }
    }    
    for( int i=0;i<4;i++){
        pair<int,int>p=find((i+1)*10+1);
        now[i][0]=(i+1)*10+1;
        now[p.x][p.y]=0;
    }

}
string get_ans_s(){
    int w2[10][10];
    string res;
    for( int i=0;i<4;i++){
        for( int j=0;j<=7;j++){
            if(j==7) w2[i][j]=0;
            else w2[i][j]=(((i+1)*10)+j+1);
            res+=(char)w2[i][j];
        }
    }
    return res;
}
int check(string &s){
    return s==ans_s;
    return 1;
}

int bfs( ){
    queue<string>q;
    set<string>vis;
    map<string,int>mp;
    init();
    ans_s=get_ans_s();
    // debugg();
    string s=hash();
    q.push(s);
    vis.insert(s);
    mp[s]=0;
    while(!q.empty()){
        string s=q.front();
        q.pop();
        rehash(s);
        // debugg();
        if(check(s)) return mp[s];
        for( int i=0;i<4;i++){
            for( int j=0;j<=7;j++){
                if(now[i][j]!=0||j==0) continue;
                int a=now[i][j-1];
                a=a+1;
                pair<int,int>p=find(a);
                if(p.x==-1||p.y==-1||a<10) continue;
                swap(now[i][j],now[p.x][p.y]);
                string ss=hash();
                if(vis.find(ss)==vis.end()){
                    mp[ss]=mp[s]+1;
                    vis.insert(ss);
                    q.push(ss);
                }
                swap(now[i][j],now[p.x][p.y]);
            }
        }
    }
    return -1;
}
int main(){
    int t;
    cin>>t;
    while(t--){
        memset(w,0,sizeof(w));
        memset(now,0,sizeof(now));
        for( int i=0;i<4;i++){
            for( int j=1;j<=7;j++){
                scanf("%d",&w[i][j]);
            }
        }
        cout<<bfs()<<endl;
        
    }
    return 0;
}

L.Eight

不太会,照网上的代码写的,自己的还没有改出来

M.Nightmare Ⅱ

双向bfs+曼哈顿距离
如果两个人的速度相同,可以用一个队列存储。
本题两个人的速度不同,需要用两个队列存储,对于ghost不需要模拟,只需用哈密顿距离判断即可
(下面代码牛客能过,hdu炸了,没交)


#include
#include
#include
#include 
#include
using namespace std;
const int N=900;
string h[N];
int zx[2],zy[2];
struct pos{
	int x,y;
}M,G;
int mov[4][2]={0,1,0,-1,1,0,-1,0};
int n,m;
int Time=0;
int vis[N][N][2];
queue<pair<int,int> >q[2];
int check(pair<int,int>p){
	int x=p.first,y=p.second;
	if(x<0||y<0||x>=n||y>=m) return 0;
	if(h[x][y]=='X'||h[x][y]=='Z') return 0;
	int dis=min(abs(x-zx[0])+abs(y-zy[0]),abs(x-zx[1])+abs(y-zy[1]));
	if(dis<=Time*2) return 0;
	return 1;
}
int bfs(int flag){
	int sum=q[flag].size();
	// cout<
	while(sum--){
		pair<int,int>now=q[flag].front();
		q[flag].pop();
		if(check(now)==0) continue;
		
		for( int i=0;i<4;i++){
			pair<int,int>temp=now;
			temp.first+=mov[i][0];
			temp.second+=mov[i][1];
			int x=temp.first,y=temp.second;
			if(check(temp)==1&&vis[x][y][flag]==0){
				if(vis[x][y][!flag]==1) return 1;
				vis[x][y][flag]=1;
				q[flag].push(temp);
			}
		}	
	}
	return 0;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
	int t;
	cin>>t;
	while(t--){
		cin>>n>>m;
		int cnt=0;
		Time=0;
		memset(vis,0,sizeof(vis));
		while(!q[1].empty()) q[1].pop();
		while(!q[0].empty()) q[0].pop();
		for( int i=0;i<n;i++){
			cin>>h[i];
			for( int j=0;j<m;j++){
				if(h[i][j]=='Z'){
					zx[cnt]=i;
					zy[cnt]=j;
					cnt++;
				}
				if(h[i][j]=='G'){
					G.x=i;
					G.y=j;
				}
				else if(h[i][j]=='M'){
					M.x=i;
					M.y=j;
				}
			}
		}
		//0代表M,可以走三步
		// cout<
		q[0].push(make_pair(M.x,M.y));
		q[1].push(make_pair(G.x,G.y));
		vis[M.x][M.y][0]=1,vis[G.x][G.y][1]=1;
		while(!q[0].empty()||!q[1].empty()){
			Time++;
			int res=1;
			for( int i=0;i<3;i++)
				if(bfs(0)==1){
					cout<<Time<<'\n';
					goto endd;
				}
			if(bfs(1)==1){
				cout<<Time<<'\n';
				goto endd;
			}
		}
		cout<<-1<<'\n';
		endd:;

	}
	return 0;
}

你可能感兴趣的:(题解,深度优先,算法,c++)