洛谷【算法1-7】搜索

P2392 kkksc03考前临时抱佛脚

题目:https://www.luogu.com.cn/problem/P2392

#include
using namespace std;
const int maxn = 25;
/*
	枚举每道题交给哪边的脑子解决,找到两边时间较大值的最小值	
*/ 
int s[5];//每个科目的题目数量 
int tim[maxn][5];//完成每道题的时间 
int Left,Right,minn,ans;

void dfs(int index,int y){
	if(index > s[y]){
		minn = min(minn,max(Left,Right));
		return;
	}
	Left +=tim[index][y];
	dfs(index+1,y);
	Left -=tim[index][y];
	Right +=tim[index][y];
	dfs(index+1,y);
	Right -=tim[index][y];
}
int main(){
	scanf("%d %d %d %d",&s[1],&s[2],&s[3],&s[4]);
	for(int i =1;i<=4;i++){
		Left = Right = 0;
		minn = 0x3fffff;
		for(int j =1;j<=s[i];j++){
			cin >> tim[j][i];
		}
		dfs(1,i);
		ans += minn;
	}
	cout<< ans;
	return 0;
}

P1443 马的遍历

#include
using namespace std;
const int maxn = 410;

int G[maxn][maxn];
bool vis[maxn][maxn]={false};
int n,m,stx,sty;
struct point{
	int x,y;
	point(int xx,int yy){
		x =xx;
		y =yy;
	}
};
int dis[8][2] = {{1,2},{-1,2},{1,-2},{-1,-2},
				{2,1},{2,-1},{-2,1},{-2,-1}};//马可以走的方向 
void bfs(int sx,int sy){//下标从1开始 
	G[sx][sy] = 0; 
	queue<point> q;
	q.push(point(sx,sy));
	vis[sx][sy] = true;
	while(!q.empty()){
		point p = q.front();
		q.pop();
		for(int i =0;i<8;i++){
			int nx = p.x+dis[i][0];
			int ny = p.y+dis[i][1];
			if(nx>0&&nx<=n&&ny>0&&ny<=m){//无越界 
				if(vis[nx][ny]==false){
					q.push(point(nx,ny));
					vis[nx][ny] = true;
					G[nx][ny] = G[p.x][p.y]+1;
				}
			}
		}
	}
}
int main(){
	memset(G,-1,sizeof(G));
	cin >>n>>m>>stx>>sty;
	bfs(stx,sty);
	for(int i =1;i<=n;i++){
		for(int j =1;j<=m;j++){
			printf("%-5d",G[i][j]);
		}
		printf("\n");
	}
	return 0;
}

P2895 [USACO08FEB]Meteor Shower S

#include
using namespace std;
const int maxn = 310;

int ma[maxn][maxn],vis[maxn][maxn];//地图(存放砸陨石时间,标记是否走过该点 
int m;//行星个数
int sx,sy,st;//陨石坐标及时间
int ans[maxn][maxn];//记录每个点的最小时间 
int dis[5][2] = {{0,0},{0,1},{0,-1},{1,0},{-1,0}};//陨石四周 
struct point{
	int x, y;
	point(int xx,int yy){
		x = xx;
		y = yy;
	}
}; 
int check(int a){//判断路过该点时,是否有陨石降落 
	if(a==-1) return 0x3fffff;//没有 
	else return a;
} 

int main(){
	cin >> m;
	memset(ma,-1,sizeof(ma));//陨石初始化为-1 
	for(int i =1;i<=m;i++){
		cin>>sx>>sy>>st;
		for(int j =0;j<5;j++){//在其及四周标记陨石 
			if(sx+dis[j][0]>=0 &&sy+dis[j][1]>=0&&(ma[sx+dis[j][0]][sy+dis[j][1]]==-1||ma[sx+dis[j][0]][sy+dis[j][1]]>st)){
				ma[sx+dis[j][0]][sy+dis[j][1]] = st;
				//如果xy坐标未出界且没有陨石砸落或砸落时间比输入时间晚,更新 
			}
		}
	}
	queue<point> q;
	vis[0][0] = 1;//标记初始点已经走过
	q.push(point(0,0));//初始点入队
	while(!q.empty()){
		point temp = q.front();
		q.pop();
		if(ma[temp.x][temp.y] == -1){
			printf("%d\n",ans[temp.x][temp.y]);
			return 0;//如果该点安全,打印走到该点的时间 
		}
		int news = ans[temp.x][temp.y]+1;//即将走的时间是现在点的下一s
		for(int i =1;i<=4;i++){//向四周走一步 
			int xx = temp.x+dis[i][0];
			int yy = temp.y+dis[i][1];
			if(xx>=0&&yy>=0&&news<check(ma[xx][yy])&&vis[xx][yy]==0){
				//如果新的点没有超边界,且陨石降落时间>现在的时间,且未走过
				q.push(point(xx,yy));
				vis[xx][yy] = 1;
				ans[xx][yy] = news;//将该点时间放入数组 
			}
		}
	}
	printf("-1\n");//出不了陨石区
	return 0; 
}

P1036 选数

#include
using namespace std;
const int maxn = 25;

bool is_Su(int x){//判断是否是素数 
	int sqr = sqrt(x*1.0);
	for(int i =2;i<sqr+1;i++){
		if(x%i==0) return false;
	}
	return true;
}
int n,k,x[maxn],ans=0,ssum = 0;
bool vis[maxn]={false};
void dfs(int cnt,int startx,int ssum){//cnt已选个数 startx从哪开始选 ssum和 
	if(cnt == k){
		if(is_Su(ssum)){
			ans++;
		}
		return;
	}
	for(int i=startx;i<n;i++){
		dfs(cnt+1,i+1,ssum+x[i]);
	}
}
int main(){
	memset(vis,0,sizeof(vis));
	scanf("%d %d",&n,&k);
	for(int i =0;i<n;i++){
		scanf("%d",&x[i]);
	}
	dfs(0,0,0);
	cout<<ans;
	return 0;
}

P2036 [COCI2008-2009#2] PERKET

#include
using namespace std;
const int maxn = 15;

int n,t[maxn],s[maxn];
int minabs=0x3fffff;
void dfs(int index,int sums,int sumt){//sums酸度,sumt甜度 
	if(index >n){
		if(sums==1&&sumt==0) return;//清水
		minabs = min(minabs,abs(sums-sumt));
		return;
	}
	//分两种情况,一种是添加 2.不添加 
	dfs(index+1,sums*s[index],sumt+t[index]);
	dfs(index+1,sums,sumt);
}
int main(){
	scanf("%d",&n);
	for(int i =1;i<=n;i++){
		scanf("%d %d",&s[i],&t[i]);
	}
	dfs(1,1,0);
	printf("%d\n",minabs);
	return 0;
}

P1433 吃奶酪

#include
using namespace std;
const int maxn = 20;

int n;
double a[20],b[20],dp[65000][20];//状压dp存距离 
double ans=1e9;//10的9次方 
bool vis[20];

double cal_dis(int x,int y){
	return sqrt((a[x]-a[y])*(a[x]-a[y])+(b[x]-b[y])*(b[x]-b[y]));//距离公式
}

void dfs(int cnt,int now,double nowdis,int b){
	//cnt吃的奶酪数,now当前在第几个奶酪的位置,nowdis距离,b用于状压 
	if(nowdis>ans) return;//剪枝
	if(cnt == n){//吃够n个奶酪 
		ans = ans<nowdis ? ans:nowdis;
		return;
	} 
	for(int i =1;i<=n;i++){
		if(vis[i]==false){
			int p = b+(1<<(i-1));//状压存状态
			if(dp[p][i]!=0 && dp[p][i]<=nowdis+cal_dis(now,i)) continue;//优化dp数组
			vis[i] = true;
			dp[p][i] = nowdis+cal_dis(now,i);
			dfs(cnt+1,i,dp[p][i],p); 
			vis[i] = false;//回溯 
		}
	}
}
int main(){
	memset(vis,0,sizeof(vis));
	scanf("%d",&n);//奶酪个数
	for(int i =1;i<=n;i++){
		scanf("%lf %lf",&a[i],&b[i]);
	} 
	dfs(0,0,0,0); 
	printf("%.2f\n",ans);
	return 0;
}

P1019 单词接龙

#include
using namespace std;
const int maxn = 25;

string str[maxn];
int n,maxlength=0,use[maxn];
char start;
int check(string str1,string str2){//计算重叠部分长度 
	for(int i =1;i<=min(str1.length(),str2.length());i++){//找出拼接长度 
		bool flag = true; 
		for(int j =0;j<i;j++){
			if(str1[str1.length()-i+j]!=str2[j])//对应位数不相同 
				flag = false;
		}
		if(flag) return i; 
	}
	return 0;//无重叠部分 
}
void dfs(string nstr,int nlength){
	maxlength = max(nlength,maxlength);
	for(int i =0;i<n;i++){
		if(use[i]<2){
			int c = check(nstr,str[i]); 
			if(c>0){
				use[i]++;
				dfs(str[i],nlength+str[i].length()-c);
				use[i]--;
			}
		}
		
	}
} 
int main(){
	memset(use,0,sizeof(use));
	scanf("%d",&n);
	for(int i =0;i<=n;i++){
		cin >> str[i];
	}
	dfs(str[n],1);//因为check函数要求
	cout<<maxlength<<endl;
	return 0;
}

P1101 单词方阵

#include
using namespace std;
const int maxn = 105;
struct point{
	int x,y;
}p[maxn];//存储路径 
char zimu[maxn][maxn];
int n;
int vis[maxn][maxn];//保存符合条件可见点 
int dis[8][2]={{1,0},{-1,0},{0,1},{0,-1},{1,1},{1,-1},{-1,-1},{-1,1}};
char str[] ="yizhong";

void dfs(int index,point p[],int x,int y,int k){//方向已定 
	if(index==7){
		for(int i =0;i<7;i++){
			vis[p[i].x][p[i].y] = 1;//将路径上的点标志为可见 
		}
		return;
	}
	else{
		int nx = x+dis[k][0];
		int ny = y+dis[k][1];
		if(index == 6||zimu[nx][ny]==str[index+1]){
			p[index].x = x;
			p[index].y = y;
			dfs(index+1,p,nx,ny,k);
		}
	}
}
int main(){
	memset(vis,0,sizeof(vis));
	scanf("%d",&n);
	for(int i =0;i<n;i++){
		cin >> zimu[i];
	}
	for(int i =0;i<n;i++){
		for(int j =0;j<n;j++){
			if(zimu[i][j]=='y'){//在y的周围找到紧挨的i 
				for(int k=0;k<8;k++){
					int x = i+dis[k][0];
					int y = j+dis[k][1];
					if(zimu[x][y]=='i'){
						dfs(0,p,i,j,k);//yi定下来之后遍历同方向k是否有接下来的字符串 
					} 
				}
			}
		}
	}
	for(int i=0;i<n;i++){
		for(int j =0;j<n;j++){
			if(vis[i][j]==1) printf("%c",zimu[i][j]);
			else printf("*");
		} 
		printf("\n");
	} 
	return 0;
}

P1032 字串变换

#include
using namespace std;
const int maxn = 7;
struct node{
	string str;
	int step;
	node(string ss,int st){
		str = ss;
		step = st;
	}
};
string A,B;
int cnt=0;//步数 
string origin[maxn];//原来字符串 
string newstr[maxn];//新转换字符串 
set<string> vis;//判重 

string exchange(string str,string substr,string rstr){//转换 
	string t = str;
	if(str.find(substr)!=string::npos){
		t.replace(t.find(substr),substr.length(),rstr);
	}
	return t;
}
void bfs(int n){
	queue<node> q;
	q.push(node(A,0));
	while(!q.empty()){
		node temp = q.front();
		q.pop();
		if(temp.str==B||temp.step>10){
			cnt = temp.step;
			return;
		}
		for(int i =0;i<n;i++){//遍历所有规则 
			string ns = exchange(temp.str,origin[i],newstr[i]);
			if(!vis.count(ns)){
				q.push(node(ns,temp.step+1)); 
				vis.insert(ns); 
			}
		}
	} 
}
int main(){
	cin>>A;
	cin>>B;
	int n=0;
	while(cin>>origin[n]>>newstr[n]){
		n++;
	}
	bfs(n);
	if(cnt>10||cnt==0)
		cout<< "NO ANSWER!" <<endl;
	else
		cout <<cnt<<endl;
	return 0;
} 

P1162 填涂颜色

#include
using namespace std;
const int maxn = 35;

int a[maxn][maxn],b[maxn][maxn];
int n;
int dis[4][2] ={{-1,0},{1,0},{0,1},{0,-1}};
void dfs(int x,int y){//将从xy开始的连通块染色 
	if(x<0||x>n+1||y<0||y>n+1||b[x][y]!=0){
		return;
	}
	b[x][y] = 1;
	for(int i =0;i<4;i++){
		dfs(x+dis[i][0],y+dis[i][1]);
	}
}
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(a[i][j]==0) b[i][j] = 0;
			else b[i][j] = 2;
		} 
	}
	dfs(0,0);
	for(int i =1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(b[i][j]==0) printf("2 ");
			else printf("%d ",a[i][j]);
		}
		printf("\n");
	}
	return 0;
}

你可能感兴趣的:(刷题)