1. 程式人生 > >【習題詳解】搜尋

【習題詳解】搜尋

搜尋習題詳解

分數字

題目描述
現有N件不可區分的物品,將它們分成10份,要求每份在1~3件之間,問有多少種方案,並按字典序輸出所有方案。
輸入格式
一個整數,表示N<=10000N<=10000。
輸出格式
第一行一個數M,表示方案數。
接下來M行每行10個整數,表示1種方案。
樣例資料
input

11
output
10
1 1 1 1 1 1 1 1 1 2
1 1 1 1 1 1 1 1 2 1
1 1 1 1 1 1 1 2 1 1
1 1 1 1 1 1 2 1 1 1
1 1 1 1 1 2 1 1 1 1
1 1 1 1 2 1 1 1 1 1
1 1 1 2 1 1 1 1 1 1
1 1 2 1 1 1 1 1 1 1
1 2 1 1 1 1 1 1 1 1
2 1 1 1 1 1 1 1 1 1

十重迴圈,暴力列舉。

#include<bits/stdc++.h>
using namespace std;
int dd[100000][10];
int main()
{
	freopen("allot.in","r",stdin);
	freopen("allot.out","w",stdout);
	int n,ans=0;
	cin>>n;
	for (int a=1;a<=3;++a)
	    for (int b=1;b<=3;++b)
	        for (int c=1;c<=3;++c)
	            for (int
d=1;d<=3;++d) for (int e=1;e<=3;++e) for (int f=1;f<=3;++f) for (int g=1;g<=3;++g) for (int h=1;h<=3;++h) for (int i=1;i<=3;++i) for
(int j=1;j<=3;++j) if (a+b+c+d+e+f+g+h+i+j==n) { ans++; dd[ans][1]=a; dd[ans][2]=b; dd[ans][3]=c; dd[ans][4]=d; dd[ans][5]=e; dd[ans][6]=f; dd[ans][7]=g; dd[ans][8]=h; dd[ans][9]=i; dd[ans][10]=j; } printf("%d\n",ans); for (int i=1;i<=ans;++i) for (int j=1;j<=10;++j) if (j==10) cout<<dd[i][j]<<'\n'; else cout<<dd[i][j]<<' '; fclose(stdin);fclose(stdout); return 0; }

流星雨

題目描述
流星雨是美麗的,但是流星落下來也能砸死人的。
有一大片流星要在海亮教育園的操場落下,而小x恰好在操場數星星。小x面臨最大的問題不是浪漫,而是保住小命。
我們把海亮教育園的操場認為是座標系的第一象限(以樣例解釋的圖例為準)。小x現在位於座標系的原點。
現在有M顆流星會落在海亮教育園的操場上,其中第i顆流星會在時刻T_i砸在座標為(X_i, Y_i)的格子裡。流星的力量會將它所在的格子,以及周圍4個相鄰的格子都化為焦土,當然小x也無法再在這些格子上行走,這樣他會被燒傷。
小x從0時刻開始逃離,他只能上下左右移動,並且一個時刻只能移動一個格子,當然,這個格子必須是完好的。
現在小x想知道,最少經過多少時刻,他可以到達一個安全的格子。
輸入格式
一個正整數M 接下來M行,每行3個整數Xi,Yi和Ti。分別表示第i顆流星落下的座標和時間。保證所有座標都在第一象限。
輸出格式
一個整數,表示最少逃離時刻。如果逃離不了,那麼輸出-1,表示小x肯定被流星砸著了。
樣例資料
input

4
0 0 2
2 1 2
1 1 2
0 3 5
output
5

題解
這道題問的是逃亡的最小時間,顯然求諸如最小距離之類的問題我們都應該選擇bfs來完成。
我們先預處理每一個點變成不能經過的點的最小時間,永遠安全的點為正無窮。
從起點開始跑廣搜,只要擴充套件節點的時候判斷當前實現經過該節點是否安全即可。
CODE

#include<bits/stdc++.h>
using namespace std;
#define maxn 400
#define maxm 60000

struct stars{
	int x,y,t;
}star[maxm];
int m,flag=1;
int v[maxn][maxn];
int d[maxn][maxn];
int danger[maxn][maxn];
int qx[maxn],qy[maxn];
int dx[4]={1,-1,0,0};
int dy[4]={0,0,1,-1};

inline void read(int &readnum)
{
    int s=0;char c=getchar();
    while (c<'0' || c>'9') c=getchar();
    while (c>='0' && c<='9') s=s*10+c-48,c=getchar();
    readnum=s;return;
}

inline bool check_in(int x,int y){
	return x>=0 && y>=0;
}

int main()
{
	freopen("meteor.in","r",stdin);
	freopen("meteor.out","w",stdout);
	int m;
	read(m);
	for (int i=1;i<=m;++i)
	{
		read(star[i].x);
		read(star[i].y);
		read(star[i].t);
	}
	memset(danger,127,sizeof(danger));
	for (int i=1;i<=m;++i) 
	{
		int px=star[i].x,py=star[i].y;
		danger[px][py]=min(star[i].t,danger[px][py]);
		for (int j=0;j<4;++j)
		{
			int nx=px+dx[j],ny=py+dy[j];
			if (check_in(nx,ny)) danger[nx][ny]=min(danger[nx][ny],star[i].t);
		}
	}//標記所有會出現危險的節點所出現危險的時間 
	memset(d,127,sizeof(d));
	int h=1,t=1;d[0][0]=0;v[0][0]=1;qx[1]=qy[1]=0;
	for (;h<=t;++h)
	{
		int px=qx[h],py=qy[h];
		if (d[px][py]<danger[px][py] && danger[px][py]>=10000000) 
		{
			cout<<d[px][py]<<endl;
			flag=0;
			break;
		}//到達安全地帶 
		for (int i=0;i<4;++i)
		{
			int nx=px+dx[i],ny=py+dy[i];
			if (!check_in(nx,ny) || v[nx][ny]) continue;
			if (d[px][py]+1<danger[nx][ny])
			{
				d[nx][ny]=d[px][py]+1;
				v[nx][ny]=1;
				qx[++t]=nx,qy[t]=ny;
			}
		}
	}
	if (flag) cout<<"-1\n";
	return 0;
}

安全回家

Zhouyibo_2023
登出

UOJ Logo 海亮教育信奧訓練平臺(校內版)
首頁

題庫
作業
比賽
積分
解題數
提交記錄
Hack!
部落格
幫助

好評差評[-7]
普及組noip2018賽前練習
B. 2安全回家
6 d 21:59:13
時間限制:1s 空間限制:256MB 輸入檔案:vuk.in 輸出檔案:vuk.out
當前24小時內您還剩19次提交本題的機會

描述
提交
解題討論區
自定義測試
返回

題目描述
Farmer John在森林裡迷路了,現在他急需要回家。
森林被分成了N*M的矩陣,每個單元格有一個字元來標示屬性,’.‘表示空地,‘V’表示Fj所在的位置,‘J’表示Fj家的位置。在森林裡有很多危險的地方,危險的地方被標記為’+’。 Fj想要在回家的路上,讓自己距離危險的地方儘可能的遠,請你幫他設計一條線路,讓這條線路上的每個點距離 危險的地方 最近的距離 最大。
假設Fj的位置為 (R,C),某個危險點的位置為 (A,B)Fj距離危險點的距離為:
|R-A| + |C-B|
當然,Fj必須要回家,也許他必須要經過危險的地方。
輸入格式
第一行兩個整數:N和M (1 ≤ N, M ≤ 500)
接下來N行,每行M個字元,範圍是:’.’, ‘+’, ‘V’, ‘J’.
資料保證肯定有’V’, ‘J’,且至少有一個’+’
輸出格式
一個整數,表示那個距離
樣例資料
input

4 4
+…


V…J
output
3
input
4 5

.+++.
.+.+.
V+.J+
output
0

題解
對於這道題,我們可以選擇做兩遍搜尋(dbfs)。
第一遍:
廣搜bfs。預處理出每一個位置距離陷進的最短距離。將多個陷進節點在廣搜前加入佇列,距離設定為0即可得到一個數字dis[i][j]表示位置i,j距離陷進的最短距離。
第二遍:
深搜dfs。因為所求的是回家的線路中距離陷進的距離的最大值,因此我們只要在dis陣列上面遍歷每一條路徑並求出這個路徑的最小值,使得最終的這個最小值最大即可;為了優化深搜,這裡加上記憶化搜尋,f[i][j]表示任何經過i,j的路徑的最小值的最大值。顯然,最後輸出記憶畫陣列的結果即可。
CODE

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

struct Node{
	int x,y;
};
Node st,ed;
int n,m,h=1,t=0,ans=0;
char a[maxn][maxn];
int d[maxn][maxn];
bool v[maxn][maxn];
Node q[maxn*maxn];
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
int f[maxn][maxn];//儲存所有最小值中的最大值 

inline void read(int &readnum)
{
    int s=0;char c=getchar();
    while (c<'0' || c>'9') c=getchar();
    while (c>='0' && c<='9') s=s*10+c-48,c=getchar();
    readnum=s;return;
}

inline int check_out(int x,int y){
	return x<1 || x>n || y<1 || y>m;
}

void readnum()
{
	read(n);
	read(m);
	for (int i=1;i<=n;++i)
	    for (int j=1;j<=m;++j)
	    {
	    	cin>>a[i][j];
	    	if (a[i][j]==43) 
			{
				v[i][j]=1;
				d[i][j]=0;
				q[++t]=(Node){i,j};
			} 
			if (a[i][j]==86) st=(Node){i,j};
			if (a[i][j]==74) ed=(Node){i,j};
	    }
}

void dfs(int x,int y,int Min)
{
	if (Min<=f[x][y]) return;
	f[x][y]=Min;
	if (x==ed.x && y==ed.y) return;
	for (int i=0;i<4;++i)
	{
		int nx=x+dx[i],ny=y+dy[i];
		if (check_out(nx,ny)) continue;
		dfs(nx,ny,min(Min,d[nx][ny]));
	} 
	return;
}

void bfs()
{
	for (;h<=t;++h)
	{
		Node p=q[h];
		for (int i=0;i<4;++i)
		{
			int nx=p.x+dx[i],ny=p.y+dy[i];
			if (check_out(nx,ny) || v[nx][ny]) continue;
			q[++t]=(Node){nx,ny};
			v[nx][ny]=1,d[nx][ny]=d[p.x][p.y]+1;
		}
	}
}

int main()
{
	freopen("vuk.in","r",stdin);
	freopen("vuk.out","w",stdout);
	memset(f,-1,sizeof(f));
	readnum();
	bfs();
	dfs(st.x,st.y,d[st.x][st.y]);
	printf("%d",f[ed.x][ed.y]);
	return 0;
}

黑洞

題目描述
李宗澤的愛好是在週末進行物理學實驗,但事與願違,實驗將N個黑洞(2 <= N <= 12, N為even)具象化在了他的農場裡,每個都有明確的座標位置。
根據他的計算,李宗澤知道將會形成N/2對連線起來的黑洞。如果黑洞A和B被連成一對,那麼任何物體進入黑洞A,將會以進入黑洞A的方向從黑洞B中出來;進入黑洞B,也會以進入時的方向從黑洞A中出來。舉例來說,黑洞A在(0,0),黑洞B在(1,0),牛玉鑫從(1/2,0)開始向X軸正方向移動,進入黑洞B,從黑洞A中出來,將繼續向X軸正方向移動,再次進入黑洞B,被困在一個迴圈裡。
李宗澤知道每一個黑洞在他的農場上的具體座標,牛玉鑫只會向X軸正方向移動,但卻不知道牛玉鑫目前的位置。
請你幫助李宗澤計算共有多少種黑洞配對方法會使在不幸的位置的牛玉鑫陷入迴圈。
輸入格式
第一行:一個正整數N;
第二到N+1行:每行兩個整數X,Y描述一個黑洞的位置,每個座標在0…1,000,000,000內。
輸出格式
一個數,代表所有的會讓牛玉鑫陷入迴圈的黑洞配對方法數。
樣例資料
input

4
0 0
1 0
1 1
0 1
有4個黑洞,形成一個正方形的迴圈。
output
2

這道題我們可以選擇深搜dfs對所有的黑洞亮亮配對,然後判環:
我們需要預處理每一個節點相同縱座標,橫座標距離它最近且在正方向時的接點編號。
設上述結果儲存在next[]裡面,與第i個節點配對點儲存在with[],則只有若干個with[next[i]]出現重複則表示出現了環。

CODE

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

struct Node{
	int x,y;
}a[maxn];
int n,ans=0;
int next[maxn],with[maxn];

inline void read(int &readnum)
{
    int s=0;char c=getchar();
    while (c<'0' || c>'9') c=getchar();
    while (c>='0' && c