【初二必做】系统复习2【bfs版块】题解

A. [USACO18OPEN,Silver]Multiplayer Moo

解析:这题挺水的。

首先跑一个bfs求连通块,附上对应的连通块标号,大小,颜色(及数字)。对相邻的连通块连边。然后枚举选择的两个颜色,对这两种颜色的连通块再求一次连通块即可。

乍一看时间复杂度 O ( m 2 c n t ) O(m^2cnt) O(m2cnt),其中cnt是连通块数目,m是颜色数目。而 c n t , m < = 25 0 2 cnt,m<=250^2 cnt,m<=2502,显然超时。

cnt是不能优化的,这是求连通块的时间代价。而枚举m时可以只枚举颜色数前50个大的,这样就过了。

#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
#include<map>

using namespace std;
const int N=255,M=255*255;

map<int,int> mp;
int ans,n,cnt,con[N][N],a[N][N],col[M],siz[M],lsh[M],num,sum[M];
int dx[5]={
    
    -1,0,1,0},dy[5]={
    
    0,1,0,-1};
bool pos[M];
vector<int> son[M];

bool cmp(int x,int y) {
    
    
	return sum[x]>sum[y];
}


void bfs(int x,int y) {
    
    
	queue<pair<int,int> > q;
	q.push(make_pair(x,y));
	con[x][y]=++cnt;
	col[cnt]=a[x][y];
	siz[cnt]=1;
	while(q.size()) {
    
    
		int x=q.front().first,y=q.front().second;
		q.pop();
		for(int i=0;i<4;i++) {
    
    
			int tx=x+dx[i],ty=y+dy[i];
			if(!con[tx][ty]&&a[x][y]==a[tx][ty]) {
    
    
				q.push(make_pair(tx,ty));
				con[tx][ty]=cnt;
				siz[cnt]++;
			}
		}
	}
}

void bfs2(int x,int a,int b) {
    
    
	int tot=siz[x];
	queue<int> q;
	q.push(x);
	pos[x]=1;
	while(q.size()) {
    
    
		int x=q.front();q.pop();
		for(int i=0;i<son[x].size();i++) {
    
    
			int y=son[x][i];
		    if(!pos[y]&&y>0&&(col[y]==lsh[a]||col[y]==lsh[b])) {
    
    
			    q.push(y);
			    pos[y]=1;
			    tot+=siz[y];
		    }
	    }
	}
	ans=max(ans,tot);
}

int main() {
    
    
	scanf("%d",&n);
	for(int i=1;i<=n;i++) 
		for(int j=1;j<=n;j++) {
    
    
			scanf("%d",&a[i][j]);
			if(!mp[a[i][j]]) {
    
    
				mp[a[i][j]]=++num;
				lsh[num]=num;
			}
			a[i][j]=mp[a[i][j]];
			sum[a[i][j]]++;
		}
		    
	for(int i=1;i<=n;i++)
	    for(int j=1;j<=n;j++) {
    
    
	    	if(!con[i][j]) {
    
    
	    		bfs(i,j);
	    		ans=max(ans,siz[con[i][j]]);
			}
		}
	for(int i=1;i<=n;i++)
	    for(int j=1;j<=n;j++) {
    
    
	    	for(int s=0;s<4;s++) {
    
    
	    		int k=i+dx[s],l=j+dy[s];
	    		int x=con[i][j],y=con[k][l];
	    		if(x!=y) {
    
    
	    			son[x].push_back(y);
	    			son[y].push_back(x);
				}
			}
		}
	printf("%d\n",ans);
	sort(lsh+1,lsh+1+num,cmp);
	for(int i=1;i<=min(num,50);i++) {
    
    
		for(int j=1;j<=min(num,50);j++) {
    
    
			if(i==j) continue;
			for(int k=1;k<=cnt;k++) pos[k]=0;
			for(int k=1;k<=cnt;k++) {
    
    
				if(!pos[k]&&(col[k]==lsh[i]||col[k]==lsh[j])) {
    
    
					bfs2(k,i,j);
				}
			}
		}
	}
	printf("%d",ans);
}

B. 1-04D. 膨胀的tyx

解析:一道中规中矩的搜索题。

显然只在给定的图中遍历,用(x,y,h,l)四元组表示状态,其中(h,l)表示在大的平面内的横纵坐标。从起点开始bfs,x>n则h++,x=0则h --;y>n则l++,y=0则l --。

当到达以前走过的点时,判断h,l是否相等,不相等则输出No;否则不加入队列(重复状态)。搜索结束后就输出Yes。

#include<bits/stdc++.h>
using namespace std;
const int N=2005;

struct node{
    
    
	int x,y,h,l;
}st;


int n,m,h[N][N],l[N][N],pos[N][N];
int dx[5]={
    
    -1,0,1,0},dy[5]={
    
    0,1,0,-1};
char s[N][N];

void bfs() {
    
    
	queue<node> q;
	q.push(st);
	pos[st.x][st.y]=1;
	while(q.size()) {
    
    
		node x=q.front();q.pop();
		//printf("%d %d %d %d\n",x.x,x.y,x.l,x.h);
		for(int i=0;i<4;i++) {
    
    
			node y=x;
			int tx=y.x+dx[i],ty=y.y+dy[i];
			if(tx>n) tx-=n,y.h++;
			if(tx==0) tx+=n,y.h--;
			if(ty>m) ty-=m,y.l++;
			if(ty==0) ty+=m,y.l--;
			y.x=tx;
			y.y=ty;
			if(s[tx][ty]=='#') continue;
			if(!pos[tx][ty]) {
    
    
				pos[tx][ty]=1;
				l[tx][ty]=y.l;
				h[tx][ty]=y.h;
				q.push(y);
			}
			else if(y.l!=l[tx][ty]||y.h!=h[tx][ty]) {
    
    
				
				printf("Yes");
				exit(0);
			}
		}
	}
}

int main() {
    
    
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	    for(int j=1;j<=m;j++) {
    
    
	    	cin>>s[i][j];
	    	if(s[i][j]=='S') st.x=i,st.y=j;
		}
	bfs();	
	printf("No");
}

C. [树声前锋杯] E 小马过河

不会。

input:
50 1250
50 100 50 50 50 50 100 100 50 100 50 100 50 100 100 50 100 100 50 100 50 100 50 50 50 100 50 100 50 50 50 50 100 50 100 50 100 50 50 100 50 50 50 50 50 50 50 50 100 100 
output:
3

D. 2-04D. 懒得说话的tyx

解析:这道题我是用数位dp做的。

注意前导0,正常的数位dp中都用dfs中参数z表示是否有前导0,这里我把它拆分成f1和f2,f1没有前导零,f2有前导零。

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e5+5;


//11111110111010
//111111101110

int n,m,f1[101][N],f2[16][N],g[16],len,tot;

int main() {
    
    
	scanf("%d%d",&n,&m);
	for(int i=1;i<n;i++) f1[1][i]=1;
	for(int i=0;i<n;i++) f2[1][i]=1;
	g[1]=1;
	f2[0][0]=1;
	for(int i=2;i<=15;i++) g[i]=g[i-1]*10%m;
	for(len=1;len<=15;len++) {
    
    
		if(f1[len][0]) break;
		for(int i=0;i<m;i++) {
    
    
			for(int j=0;j<n;j++) {
    
    
				f1[len+1][(i*10+j)%m]|=f1[len][i];
				f2[len+1][(i*10+j)%m]|=f2[len][i];
			}
		}
	}
	//printf("%d\n",len);
	for(int i=1;i<=len;i++) {
    
    
		//printf("%d\n",tot);
		for(int j=0;j<n;j++) {
    
    
			if(i==1&&j==0) continue;
			if(f2[len-i][(tot-(j*g[len-i+1]%m)+m)%m]) {
    
    
				printf("%d",j);
				tot=(tot-(j*g[len-i+1]%m)+m)%m;
				break;
			}
		}
	}
}

猜你喜欢

转载自blog.csdn.net/cqbzlydd/article/details/108651798