今天網絡賽又被虐了,哎,還是太菜,還是忘了吧,重要的是努力,是提升,黑暗總會過去的!!!希望一直都有,只要你肯堅持!從現在做起,重拾信心,重拾希望,不要企圖一步登天,不要想那些虛無縹緲的未來,腳踏實地,向前進!
現在就把前陣子寫的專題一做個總結吧。
bfs:遞歸實現,所以容易超時爆棧,而且判重、標記要麼都在中間,要麼都在開頭(根據寫法類型而定,“先判再走”or"走後再判")【見A題】。回溯恢復要麼都在本層,要麼都在下一層。【見A題】
如果題目要求最優解,找到目標後,每次還要進行比較取優。
如果題目中,每一步可以任意走的話,可以採用。
bfs:循環實現,不會爆棧。判重、標記要麼都在入隊前,要麼都在出隊後。
第一次找到目標後,就是最優解,無需比較取優。
如果題目中,每一步有規定,只能特定地走,可以採用。
可以打印路徑,只要用數組模擬隊列,並且在節點的結構體中加一個pre就行,路徑的第一個節點的pre設爲-1,打印時用一個遞歸函數,終止條件就是pre!=-1。
A題:
題意:
給你一個n*n的棋盤,棋盤上只有'#'位置可以放置棋子,要求放置k個棋子,棋子每一行,每一列只能有一個棋子。
思路:
由於n,k很小,不超過8,直接暴搜就行,看了一下自己的提交記錄,發現並不是1A,任何的非1A都可能導致一場比賽的失敗,這也暴露了自己對暴搜寫法有一定的問題。
先看一下我的AC代碼:
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n) scanf("%d",&n);
#define Scans(s) scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
ll inv(ll a,ll m) { if(a == 1) return 1; return inv(m%a,m)*(m-m/a)%m; }
int lowbit(int x) { return x & (-x); }
const int maxn = 500000 + 100;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
int n,k;
char mp[10][10];
int ans;
int vis1[10];
int vis2[10];
void dfs(int now, int cnt){
if(cnt == k){
ans++;
return;
}
for(int i = now; i <= n; ++i){
if(vis1[i]) continue;
for(int j = 1; j <= n; ++j){
if(vis2[j]) continue;
if(mp[i][j] == '#'){
vis1[i] = 1;
vis2[j] = 1;
dfs(i+1,cnt+1);
vis1[i] = 0;
vis2[j] = 0;
}
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
//Fin;
#endif // ONLINE_JUDGE
while(scanf("%d%d",&n,&k) == 2){
getchar();
if(n == -1 && k == -1) break;
fo(i,1,n+1){
fo(j,1,n+1)
scanf("%c",&mp[i][j]);
getchar();
}
ans = 0;
dfs(1,0);
printf("%d\n",ans);
}
return 0;
}
我上面的AC代碼就是典型的判斷後再走。
再看一下我的失敗代碼:
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n) scanf("%d",&n);
#define Scans(s) scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
ll inv(ll a,ll m) { if(a == 1) return 1; return inv(m%a,m)*(m-m/a)%m; }
int lowbit(int x) { return x & (-x); }
const int maxn = 500000 + 100;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
int n,k;
char mp[10][10];
int ans;
int vis1[10];
int vis2[10];
void dfs(int now, int cnt){
if(cnt == k){
ans++;
return;
}
if(vis1[now]) return;
for(int i = now; i <= n; ++i){
for(int j = 1; j <= n; ++j){
if(vis2[j]) continue;
if(mp[i][j] == '#'){
vis1[i] = 1;
vis2[j] = 1;
dfs(now+1,cnt+1);
vis1[i] = 0;
vis2[j] = 0;
}
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
//Fin;
#endif // ONLINE_JUDGE
while(scanf("%d%d",&n,&k) == 2){
getchar();
if(n == -1 && k == -1) break;
fo(i,1,n+1){
fo(j,1,n+1)
scanf("%c",&mp[i][j]);
getchar();
}
ans = 0;
dfs(1,0);
printf("%d\n",ans);
}
return 0;
}
不難發現失敗代碼與ac代碼就差別在對vis1數組的判重的位置,這告訴我,既然選擇“判斷後再走”,就必須嚴格遵循“先判重,然後走”,不能又在開頭再判重。
另外,又參考了一下別人的代碼:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
char a[10][10];
int ans=0;
int n,k;
int visit [10];
void bfs(int cnt,int x,int y)
{
if(cnt==k) {
ans++;
return ;
}
visit[y]=1;
for(int i=x+1;i<n;i++){
for(int j=0;j<n;j++){
if(visit[j]==0&&a[i][j]=='#') {
bfs(cnt+1,i,j);
}
}
}
visit[y]=0;
}
int main()
{
while(~scanf("%d%d",&n,&k)){
if(n==-1&&k==-1) {
break;
}
for(int i=0;i<n;i++) {
scanf("%s",a[i]);
}
int x,y;
ans=0;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(a[i][j]=='#') {
memset(visit,0,sizeof(visit));
bfs(1,i,j);
}
}
}
printf("%d\n",ans);
}
}
他的代碼在恢復狀態的寫法與我不同(對visit數組),其實兩種方法都可以,我的放在裏面,就是等它回到原來這一層,再給恢復,而他的代碼,則是在進入下一層再標記,然後在回到本層才恢復標記。
B題:
題意:
給一個三維的迷宮,’#‘不能走,’.'表示可以走,'S'表示起點,'E'表示終點,求最短逃離時間,若不能逃離,輸出“Trapped!”,否則輸出“Escaped in x minute(s).”。
思路:對於每一步行走有限制的題目,一般採用bfs,而每一步可以任意行走的題,例如上一題,可以採用dfs,本次採用bfs,對六個方向進行試探,入隊...
代碼1(極其冗雜易錯的代碼):
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n) scanf("%d",&n);
#define Scans(s) scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
ll inv(ll a,ll m) { if(a == 1) return 1; return inv(m%a,m)*(m-m/a)%m; }
int lowbit(int x) { return x & (-x); }
const int maxn = 500000 + 100;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
typedef struct Node{
int x,y,z;
}Node;
typedef struct node{
int step;
Node loc;
}node;
int l,r,c;
char mp[100][100][100];
int vis[100][100][100];
Node start,end;
queue<node> que;
int ans;
void bfs(){
while(!que.empty())
que.pop();
me(vis,0);
ans = 0;
node Begin;
Begin.step = 0;
Begin.loc.x = start.x;
Begin.loc.y = start.y;
Begin.loc.z = start.z;
que.push(Begin);
vis[start.z][start.x][start.y] = 1;
while(!que.empty()){
node now = que.front();
que.pop();
int step = now.step;
int z = now.loc.z; int x = now.loc.x; int y = now.loc.y;
//printf("now: step:%d z:%d x:%d y:%d\n",step,z,x,y);
if(z == end.z && x == end.x && y == end.y){
//printf("success!! step:%d z:%d x:%d y:%d\n",step,z,x,y);
ans = step;
return;
}
//printf("上: vis:%d mp:%c\n",vis[z+1][x][y],mp[z+1][x][y]);
if(z+1 <= l && !vis[z+1][x][y] && mp[z+1][x][y] != '#'){
//printf("上: step:%d z:%d x:%d y:%d\n",step+1,z+1,x,y);
node temp;
temp.step = step+1;
temp.loc.z = z+1; temp.loc.x = x; temp.loc.y = y;
vis[z+1][x][y] = 1;
que.push(temp);
}
//printf("下: vis:%d mp:%c\n",vis[z-1][x][y],mp[z-1][x][y]);
if(z-1 >= 1 && !vis[z-1][x][y] && mp[z-1][x][y] != '#'){
//printf("下: step:%d z:%d x:%d y:%d\n",step+1,z-1,x,y);
node temp;
temp.step = step+1;
temp.loc.z = z-1; temp.loc.x = x; temp.loc.y = y;
vis[z-1][x][y] = 1;
que.push(temp);
}
//printf("右: vis:%d mp:%c\n",vis[z][x+1][y],mp[z][x+1][y]);
if(x+1 <= r && !vis[z][x+1][y] && mp[z][x+1][y] != '#'){
//printf("右: step:%d z:%d x:%d y:%d\n",step+1,z,x+1,y);
node temp;
temp.step = step+1;
temp.loc.z = z; temp.loc.x = x+1; temp.loc.y = y;
vis[z][x+1][y] = 1;
que.push(temp);
}
//printf("左: vis:%d mp:%c\n",vis[z][x-1][y],mp[z][x-1][y]);
if(x-1 >= 1 && !vis[z][x-1][y] && mp[z][x-1][y] != '#'){
//printf("左: step:%d z:%d x:%d y:%d\n",step+1,z,x-1,y);
node temp;
temp.step = step+1;
temp.loc.z = z; temp.loc.x = x-1; temp.loc.y = y;
vis[z][x-1][y] = 1;
que.push(temp);
}
//printf("前: vis:%d mp:%c\n",vis[z][x][y+1],mp[z][x][y+1]);
if(y+1 <= c && !vis[z][x][y+1] && mp[z][x][y+1] != '#'){
//printf("前: step:%d z:%d x:%d y:%d\n",step+1,z,x,y+1);
node temp;
temp.step = step+1;
temp.loc.z = z; temp.loc.x = x; temp.loc.y = y+1;
vis[z][x][y+1] = 1;
que.push(temp);
}
//printf("後: vis:%d mp:%c\n",vis[z][x][y-1],mp[z][x][y-1]);
if(y-1 >= 1 && !vis[z][x][y-1] && mp[z][x][y-1] != '#'){
//printf("後: step:%d z:%d x:%d y:%d\n",step+1,z,x,y-1);
node temp;
temp.step = step+1;
temp.loc.z = z; temp.loc.x = x; temp.loc.y = y-1;
vis[z][x][y-1] = 1;
que.push(temp);
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
Fin;
#endif // ONLINE_JUDGE
while(scanf("%d%d%d",&l,&r,&c) == 3){
//printf("l:%d r:%d c:%d\n",l,r,c);
//getchar();
if(!l && !r && !c) break;
me(mp,0);
int i,j,k;
for(i = 1; i <= l; ++i){
for(j = 1; j <= r; ++j){
scanf("%s",mp[i][j]+1);
for(k = 1; k <= c; ++k){
if(mp[i][j][k] == 'S'){
start.x = j; start.y= k; start.z = i;
}
if(mp[i][j][k] == 'E'){
end.x = j; end.y= k; end.z = i;
}
}
//getchar();
}
//getchar();
}
/*for(int i = 1; i <= l; ++i){
for(int j = 1; j <= r; ++j){
for(int k = 1; k <= c; ++k){
cout << mp[i][j][k];
}
cout << endl;
}
cout << endl;
}
printf("start: x:%d y:%d z:%d\n",start.x, start.y, start.z);
printf("end: x:%d y:%d z:%d\n",end.x, end.y, end.z);*/
ans = 0;
bfs();
if(ans == 0)
cout << "Trapped!" << endl;
else
printf("Escaped in %d minute(s).\n",ans);
}
return 0;
}
其實上面的bfs的代碼量可以縮短很多的,首先可以寫一個check函數,判斷點是否合理,另外,六個方向可以用三個一維數組(1*6)表示。
代碼2(簡潔代碼,其中的六個方向的表示,代碼中提供了兩種方法,個人喜歡沒被註釋掉的那種方法):
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n) scanf("%d",&n);
#define Scans(s) scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
ll inv(ll a,ll m) { if(a == 1) return 1; return inv(m%a,m)*(m-m/a)%m; }
int lowbit(int x) { return x & (-x); }
const int maxn = 500000 + 100;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
int l,r,c;
char mp[35][35][35];
int vis[35][35][35];
//int dire[6][3] = {{0,0,1},{0,0,-1},{1,0,0},{-1,0,0},{0,1,0},{0,-1,0}};
int dirx[] = {0,0,1,-1,0,0};
int diry[] = {0,0,0,0,1,-1};
int dirz[] = {1,-1,0,0,0,0};
int stx,sty,stz,edx,edy,edz;
struct node{
int x,y,z;
int step;
};
queue<node> que;
void Init(){
while(!que.empty())
que.pop();
me(vis,0);
}
int check(node temp){
if(!(1 <= temp.z && temp.z <= l)) return 0;
if(!(1 <= temp.x && temp.x <= r)) return 0;
if(!(1 <= temp.y && temp.y <= c)) return 0;
if(vis[temp.x][temp.y][temp.z]) return 0;
if(mp[temp.z][temp.x][temp.y] == '#') return 0;
return 1;
}
int dfs(){
Init();
node startt;
startt.x = stx, startt.y = sty, startt.z = stz; startt.step = 0;
que.push(startt);
vis[stx][sty][stz] = 1;
while(!que.empty()){
node now = que.front();
que.pop();
int x = now.x; int y = now.y; int z = now.z; int step = now.step;
if(x == edx && y == edy && z == edz){
return step;
}
fo(i,0,6){
node nextt = now;
//nextt.x += dire[i][0];
//nextt.y += dire[i][1];
//nextt.z += dire[i][2];
nextt.x += dirx[i]; nextt.y += diry[i]; nextt.z += dirz[i];
nextt.step++;
if(check(nextt)){
que.push(nextt);
vis[nextt.x][nextt.y][nextt.z] = 1;
}
}
}
return 0;
}
int main()
{
#ifndef ONLINE_JUDGE
Fin;
#endif // ONLINE_JUDGE
while(cin >> l >> r >> c){
if(!l && !r && !c) break;
me(mp,0);
fo(i,1,l+1){
fo(j,1,r+1){
scanf("%s",mp[i][j]+1);
fo(k,1,c+1){
if(mp[i][j][k] == 'S'){
stx = j; sty = k; stz = i;
}
if(mp[i][j][k] == 'E'){
edx = j; edy = k; edz = i;
}
}
}
}
int ans = dfs();
if(ans)
printf("Escaped in %d minute(s).\n",ans);
else
printf("Trapped!\n");
}
return 0;
}
C題
題意:
在一個一維空間裏,給你一個初始位置,以及一個目標位置,你有三種方式可以走,1是左移一個單位,2是右移一個單位,3是位置擴爲兩倍,要求位置在[0,1e5]之間。問到達目標位置最少需要多少步?
思路:
限定了每步只可有三種選擇,那麼選擇dfs,再注意一下邊界就行。
代碼:
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n) scanf("%d",&n);
#define Scans(s) scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
ll inv(ll a,ll m) { if(a == 1) return 1; return inv(m%a,m)*(m-m/a)%m; }
int lowbit(int x) { return x & (-x); }
const int maxn = 100000 + 100;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
struct Node{
int step,loc;
Node(int a, int b){
step = a;
loc = b;
}
};
int n,k;
int vis[maxn];
queue<Node> que;
int ans;
int check(int loc){
if(!(0 <= loc && loc <= maxn)) return 0;
if(vis[loc]) return 0;
return 1;
}
void bfs(){
Node start(0,n);
if(n == k)
return;
que.push(start);
vis[n] = 1;
while(!que.empty()){
Node now = que.front();
que.pop();
int step = now.step; int loc = now.loc;
//printf("step:%d loc:%d\n",step,loc);
if(loc == k){
ans = step;
return ;
}
if(check(loc-1)){
Node Next(step+1,loc-1);
que.push(Next);
//printf("loc:%d step:%d\n",Next.loc,Next.step);
vis[loc-1] = 1;
}
if(check(loc+1)){
Node Next(step+1,loc+1);
que.push(Next);
vis[loc+1] = 1;
}
if(check(loc*2)){
Node Next(step+1,loc*2);
que.push(Next);
vis[loc*2] = 1;
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
//Fin;
#endif // ONLINE_JUDGE
cin >> n >> k;
ans = 0;
bfs();
cout << ans << endl;
return 0;
}
D題:
題意:
給N*M的01矩陣,對每一個位置,可以進行01翻轉,翻轉的同時,它的上下左右的四個位置也同時進行01翻轉。問最少需要多少次翻轉,可以使矩陣全0,輸出每個位置的翻轉次數。
思路:
首先,明確一點,每一個位置翻轉2次,將回到原狀態,翻轉3次,等同於翻轉1次,因而每個位置最多翻轉1次。
另外,對於這種翻轉問題,而且是對周圍的格子有影響的翻轉,一般並不需要確定全部格子,只需確定一部分格子,剩下的格子在確定好了的格子的影響下,也將被確定。而對於本題,你只要確定第一行的格子,那麼第二行也就確定了(第二行的分佈方式得需將第一行變爲全0,就是說第一行的第i列爲1時,相應的第二行的第i列要翻轉一次),同理,第二行確定後,第三行受第二行的約束,也將確定......所以只要枚舉第一行就行,可以採用dfs,暴力枚舉第一行,對於第一行的每一個位置,進行01試探。
代碼:
#include <map>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n) scanf("%d",&n);
#define Scans(s) scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 110000 + 5;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
int mp[20][20];
int temp[20][20];
int ans[20][20];
int answer[20][20];
int cnt;
int m,n;
int flag;
void flip(int x, int y){
if(x-1 >= 1)
temp[x-1][y] = !temp[x-1][y];
if(x+1 <= m)
temp[x+1][y] = !temp[x+1][y];
if(y-1 >= 1)
temp[x][y-1] = !temp[x][y-1];
if(y+1 <= n)
temp[x][y+1] = !temp[x][y+1];
temp[x][y] = !temp[x][y];
}
int Count(){
int sum = 0;
fo(i,1,m+1)
fo(j,1,n+1)
if(ans[i][j] == 1)
sum++;
return sum;
}
void Copy(){
fo(i,1,m+1)
fo(j,1,n+1)
answer[i][j] = ans[i][j];
}
int check(){
for(int i = 1; i <= m; ++i){
for(int j = 1;j <= n; ++j)
temp[i][j] = mp[i][j];
}
fo(i,1,m+1){
fo(j,1,n+1){
if(ans[i][j] == 1)
flip(i,j);
}
if(i != m){
fo(j,1,n+1)
ans[i+1][j] = temp[i][j];
}
}
fo(i,1,m+1){
fo(j,1,n+1){
if(temp[i][j] == 1)
return 0;
}
}
return 1;
}
void dfs(int y){
if(y == n){
ans[1][y] = 0;
if(check()){
flag = 1;
int num = Count();
if(num < cnt){
Copy();
cnt = num;
}
return;
}
ans[1][y] = 1;
if(check()){
int num = Count();
flag = 1;
if(num < cnt){
Copy();
cnt = num;
}
}
return;
}
ans[1][y] = 0;
dfs(y+1);
ans[1][y] = 1;
dfs(y+1);
}
int main()
{
#ifndef ONLINE_JUDGE
Fin;
#endif // ONLINE_JUDGE
cin >> m >> n;
fo(i,1,m+1)
fo(j,1,n+1)
cin >> mp[i][j];
me(ans,0);
flag = 0;
cnt = INF;
dfs(1);
if(flag == 0)
cout << "IMPOSSIBLE" << endl;
else{
print2();
}
return 0;
}
E題:
題意:
給你一個數n,要求輸出一個n的倍數m,其中m是隻有0和1的十進制數。
思路:
這題的n是不超過200,而m不超過100位,也就是10^(100),當時看了就慌了,這個m沒法用任何類型來存啊。。太大了啊。。。後來想想,n不超過200,那麼相應的m應該也不會達到100位吧,就用long long試試,然後就過了。。。
由於m只有0和1,那麼對於m的每一位進行01試探就行。DFS和BFS都行吧。
我用的bfs(雙端口bfs),另外,本題是special judge,也就是可能存在多解,輸出一個就行,所以輸出結果和樣例不同也沒事。
代碼:
#include <map>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n) scanf("%d",&n);
#define Scans(s) scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 110000 + 5;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
queue<ll> que;
ll n;
void bfs(){
while(!que.empty())
que.pop();
que.push(1);
while (!que.empty()) {
ll temp = que.front();
que.pop();
if(temp%n == 0){
cout << temp << endl;
return;
}
que.push(temp*10);
que.push(temp*10+1);
}
}
int main()
{
#ifndef ONLINE_JUDGE
//Fin;
#endif // ONLINE_JUDGE
while(cin >> n){
if(!n) break;
//printf("n:%lld\n",n);
bfs();
}
return 0;
F題:
題意:
有a,b兩個質數,要求通過一些轉換,使a變爲b,每次變換,只能變換一位,而且變換後的數也得是質數,問最少變換幾次,可以得到b。a,b都是四位數。
思路:
由於只有四位數,然後每次只能改變一位數,那麼採用bfs,可以對每一位的數依次嘗試0~9,一共36種嘗試,如果改變一位數後是質數,就入隊,直到找到b。
注意點:
由於要對每一位進行改變,所以採用字符數組來存數字,方便對每一位進行操作,然後還得把字符數組表示的數字轉化爲數字,來判斷是否是質數。所以要寫一個字符數組的函數:
int chartonum(char s[]){
int num = 0;
for(int i = 0; i < 4; ++i){ //一個數字的越前位,越大,所以正向處理
num = num*10 + (s[i]-'0');
}
return num;
}
代碼:
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define fi(a,n,val) fill(a,a+n,val)
#define Scand(n) scanf("%d",&n)
#define Scans(s) scanf("%s",s)
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 110000 + 5;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
int n;
char st[5],ed[5];
int ans;
bool notprime[10005];
int vis[10005];
struct node{
int num;
char numm[5];
int step;
};
void Init(){
memset(notprime, false, sizeof(notprime));
notprime[0] = notprime[1] = true;
for(int i = 2; i < 10005; ++i){
if(!notprime[i]){
if(i > 10005/i) continue;
for(int j = i*i; j < 10005; j +=i)
notprime[j] = true;
}
}
}
int chartonum(char s[]){
int num = 0;
for(int i = 0; i < 4; ++i){
num = num*10 + (s[i]-'0');
}
return num;
}
void bfs(){
queue<node> que;
node startt;
strcpy(startt.numm, st);
startt.num = chartonum(st);
startt.step = 0;
que.push(startt);
vis[startt.num] = 1;
while (!que.empty()) {
node now = que.front();
if(strcmp(now.numm, ed) == 0){
ans = min(ans, now.step);
return;
}
que.pop();
// printf("now: num:%d step:%d\n",now.num,now.step);
for(int i = 0; i < 4; ++i){
char temp[5];
strcpy(temp, now.numm);
// printf("i:%d temp:%s\n",i,temp);
for(int j = 0; j < 10; ++j){
temp[i] = '0'+j;
// printf("j:%d temp[%d]:%c\n",j,i,temp[i]);
if(strcmp(temp, now.numm) == 0)
continue;
int tempnum = chartonum(temp);
if(notprime[tempnum]) continue;
if(tempnum < 1000 || tempnum > 9999) continue;
if(vis[tempnum]) continue;
node nextt;
strcpy(nextt.numm, temp);
nextt.num = chartonum(nextt.numm);
nextt.step = now.step+1;
que.push(nextt);
vis[nextt.num] = 1;
// printf("success\n");
}
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
//Fin;
#endif // ONLINE_JUDGE
Init();
int n;
Scand(n);
fo(i, 0, n){
me(st, 0); me(ed, 0);
Scans(st); Scans(ed);
// printf("st:%s\ned:%s\n",st,ed);
ans = INF;
me(vis, 0);
bfs();
printf("%d\n",ans);
}
return 0;
}
G題:
題意:
類似於洗牌,給你兩個字符串s1,s2,將s1,s2交叉插入,形成一個新字符串s,問能否得到給定的字符串。
思路:
由於整個過程都是固定唯一的,可以直接模擬這個過程,每次操作完,判斷是否達到要求就行。其實就是一個遞歸函數,算不上dfs,好吧好吧,其實dfs不就是暴力遞歸嗎。。。不過有一個問題就是,既然是遞歸,那麼總得有一個終止條件吧,手算髮現,經過一定次數的操作之後,s1,s2會回到一開始的s1,s2,那麼以此作爲終止條件就行。
技巧:
將s分割爲s1和s2時,採用了strncpy函數。strncpy(字符數組名稱,起始位置,切割長度)
代碼:
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define fi(a,n,val) fill(a,a+n,val)
#define Scand(n) scanf("%d",&n)
#define Scand2(a,b) scanf("%d%d",&a,&b)
#define Scand3(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define Scand4(a,b,c,d) scanf("%d%d%d%d",&a,&b,&c,&d)
#define Scans(s) scanf("%s",s)
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 1e2 + 50;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
char a[maxn], b[maxn], c[2*maxn], together[2*maxn];
int success,cnt;
void fun(char a[], char b[]){
int len = strlen(a);
char temp[maxn*2];
int ind = 0;
for(int i = 0; i < len; ++i)
together[ind++] = b[i], together[ind++] = a[i];
// printf("temp:%s\n",temp);
// return temp;
}
void dfs(char x[], char y[]){
// printf("before:x:%s\ny:%s\n",x,y);
// printf("a:%s\nb:%s\nc:%s\n",a,b,c);
if(strcmp(x, a) == 0 && strcmp(y, b) == 0 && cnt){
return;
}
// char* together;
fi(together, maxn-5, 0);
fun(x, y);
cnt++;
// printf("together:%s\n",together);
if(strcmp(together, c) == 0){
success = 1;
return;
}
int len = strlen(together);
strncpy(x, together, len/2); strncpy(y, together+len/2, len/2);
// printf("after:x:%s\ny:%s\n",x,y);
dfs(x, y);
}
int main()
{
#ifndef ONLINE_JUDGE
//Fin;
#endif // ONLINE_JUDGE
int T;
Scand(T);
for(int i = 1; i <= T; ++i){
fi(a, maxn-5, 0); fi(b, maxn-5, 0); fi(c, maxn-5, 0); fi(together, maxn-5, 0);
int n;
Scand(n);
Scans(a), Scans(b), Scans(c);
success = 0, cnt = 0;
// printf("a:%s\nb:%s\nc:%s\n",a,b,c);
char aa[maxn],bb[maxn];
strcpy(aa, a); strcpy(bb, b);
dfs(aa,bb);
if(success){
printf("%d %d\n",i,cnt);
}else{
printf("%d %d\n",i,-1);
}
}
return 0;
}
H題:
題意:
給你兩個容器,分別能裝下A升水和B升水,並且可以進行以下操作
FILL(i) 將第i個容器從水龍頭裏裝滿(1 ≤ i ≤ 2);
DROP(i) 將第i個容器抽乾
POUR(i,j) 將第i個容器裏的水倒入第j個容器(這次操作結束後產生兩種結果,一是第j個容器倒滿並且第i個容器依舊有剩餘,二是第i個容器裏的水全部倒入j中,第i個容器爲空)
現在要求你寫一個程序,來找出能使其中任何一個容器裏的水恰好有C升,找出最少操作數並給出操作過程
思路:
在結構體中設置兩個變量來表示兩個瓶子中當前的水量。用bfs來遍歷所有的可能,每一步有三種可能的操作。
另外由於要輸出路徑,所以要用數組模擬隊列,並在結構體中設置了pre,路徑中的第一個節點,也就是第一個入隊的節點,將其的pre設爲-1,之後入隊的節點的pre設爲父節點的數組下標。最後用遞歸函數打印路徑,遞歸的終止條件是pre==-1。
還有就是由於選擇第一種操作兩種可能,所以進入循環前,要先push兩個節點,也就是雙入口bfs。
代碼:
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define fi(a,n,val) fill(a,a+n,val)
#define Scand(n) scanf("%d",&n)
#define Scand2(a,b) scanf("%d%d",&a,&b)
#define Scand3(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define Scand4(a,b,c,d) scanf("%d%d%d%d",&a,&b,&c,&d)
#define Scans(s) scanf("%s",s)
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 1e6 + 50;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
struct node{
int id,order;
int step,resultt1,resultt2;
int pre;
};
node que[maxn];
int a,b,c;
int cnt = 0;
int success;
int vis[1000][1000];
void print(int num){
if(num == -1){
return;
}
print(que[num].pre);
if(que[num].order == 1){
printf("FILL(%d)\n",que[num].id);
}
else if(que[num].order == 2){
printf("DROP(%d)\n",que[num].id);
}else if(que[num].order == 3){
printf("POUR(%d,%d)\n",que[num].id,3-que[num].id);
}
}
void bfs(){
me(que, 0); me(vis, 0); success = 0;
node startt;
startt.order = 1; startt.id = 1; startt.pre = -1; startt.step = 1; startt.resultt1 = a; startt.resultt2 = 0;
int front = 0, rear = 0;
que[rear++] = startt;
startt.id = 2; startt.resultt2 = b; startt.resultt1 = 0;
que[rear++] = startt;
vis[0][0] = 1;
int flag = 0;
while (front < rear) {
node now = que[front];
if(now.resultt1 == c || now.resultt2 == c){
success = 1;
printf("%d\n",now.step);
print(front);
return ;
}
if(vis[now.resultt1][now.resultt2]){
front++;
continue;
}
vis[now.resultt1][now.resultt2] = 1;
if(now.resultt1 != a){
node nextt;
nextt.id = 1; nextt.order = 1; nextt.pre = front; nextt.resultt1 = a; nextt.step = now.step+1; nextt.resultt2 = now.resultt2;
que[rear++] = nextt;
}
if(now.resultt1 != 0){
node nextt;
nextt.id = 1; nextt.order = 2; nextt.pre = front; nextt.resultt1 = 0; nextt.step = now.step+1; nextt.resultt2 = now.resultt2;
que[rear++] = nextt;
}
if(now.resultt1 != 0){
node nextt;
nextt.id = 1; nextt.order = 3; nextt.pre = front; nextt.step = now.step+1;
if(now.resultt1+now.resultt2 > b){
nextt.resultt2 = b;
nextt.resultt1 = now.resultt1-(b-now.resultt2);
}else{
nextt.resultt2 = now.resultt1+now.resultt2;
nextt.resultt1 = 0;
}
que[rear++] = nextt;
}
if(now.resultt2 != b){
node nextt;
nextt.id = 2; nextt.order = 1; nextt.pre = front; nextt.resultt2 = b; nextt.step = now.step+1; nextt.resultt1 = now.resultt1;
que[rear++] = nextt;
}
if(now.resultt2 != 0){
node nextt;
nextt.id = 2; nextt.order = 2; nextt.pre = front; nextt.resultt2 = 0; nextt.step = now.step+1; nextt.resultt1 = now.resultt1;
que[rear++] = nextt;
}
if(now.resultt2 != 0){
node nextt;
nextt.id = 2; nextt.order = 3; nextt.pre = front; nextt.step = now.step+1;
if(now.resultt1+now.resultt2 > a){
nextt.resultt1 = a;
nextt.resultt2 = now.resultt2-(a-now.resultt1);
}else{
nextt.resultt1 = now.resultt1+now.resultt2;
nextt.resultt2 = 0;
}
que[rear++] = nextt;
}
front++;
}
}
int main()
{
#ifndef ONLINE_JUDGE
//Fin;
#endif // ONLINE_JUDGE
while(Scand3(a, b, c) == 3){
bfs();
if(!success)
printf("impossible\n");
}
return 0;
}
I題:
題意:
兩個熊孩子在n*m的平地上放火玩,#表示草,兩個熊孩子分別選一個#格子點火,火可以向上向下向左向右在有草的格子蔓延,點火的地方時間爲0,蔓延至下一格的時間依次加一。求燒完所有的草需要的最少時間。如不能燒完輸出-1。
思路:
思路很簡單,這題明顯是雙入口的bfs。先把可以燒的位置存進來,然後一個二重循環,遍歷bfs 兩個入口的位置,找出最優解就行。(這裏要比較取優的原因在於,要進行多個bfs,每一個bfs求得的是最優解,然後在這些個最優解中取優)。
代碼:
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define fi(a,n,val) fill(a,a+n,val)
#define Scand(n) scanf("%d",&n)
#define Scand2(a,b) scanf("%d%d",&a,&b)
#define Scand3(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define Scand4(a,b,c,d) scanf("%d%d%d%d",&a,&b,&c,&d)
#define Scans(s) scanf("%s",s)
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 1e4 + 50;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
struct node{
int x,y,step;
};
int n,m;
char mp[100][100];
int vis[100][100];
int ans, sum;
queue<node> que;
vector<node> v;
int dirx[] = {1,-1,0,0};
int diry[] = {0,0,1,-1};
void bfs(int x1, int y1, int x2, int y2){
me(vis, 0);
ans = 0;
while (!que.empty()) {
que.pop();
}
node startt;
startt.x = x1; startt.y = y1; startt.step = 0;
que.push(startt);
vis[x1][y1] = 1;
startt.x = x2; startt.y = y2; startt.step = 0;
que.push(startt);
vis[x2][y2] = 1;
while (!que.empty()) {
node now = que.front();
que.pop();
int xx = now.x; int yy = now.y; int stepp = now.step;
ans = stepp;
// int flag = 0;
for(int i = 0; i < 4; ++i){
int xxx = xx + dirx[i]; int yyy = yy + diry[i];
if(!(0 <= xxx && xxx < n) || !(0 <= yyy && yyy < m))
continue;
node nextt;
nextt.x = xxx; nextt.y = yyy; nextt.step = stepp+1;
if(mp[xxx][yyy] == '#' && !vis[xxx][yyy]){
que.push(nextt);
vis[xxx][yyy] = 1;
}
}
}
}
int judge(){
fo(i, 0, n)
fo(j, 0, m)
if(mp[i][j] == '#' && !vis[i][j])
return 0;
return 1;
}
int main()
{
#ifndef ONLINE_JUDGE
//Fin;
#endif // ONLINE_JUDGE
int T;
while(Scand(T) != EOF){
for(int t = 1; t <= T; ++t){
Scand2(n, m);
me(mp, 0); me(vis, 0);
for(int i = 0; i < n; ++i)
Scans(mp[i]);
sum = 0;
v.clear();
for(int i = 0; i < n; ++i){
for(int j = 0; j < m; ++j){
if(mp[i][j] == '#'){
sum++;
node temp;
temp.x = i; temp.y = j; temp.step = 0;
v.push_back(temp);
}
}
}
int result = INF;
for(int i=0;i<v.size();i++)
{
for(int j=i;j<v.size();j++)
{
bfs(v[i].x,v[i].y,v[j].x,v[j].y);
int ok = judge();
if(ok)
{
result = min(result,ans);
}
}
}
if(result == INF)
result = -1;
printf("Case %d: %d\n",t,result);
}
}
return 0;
}
K題:
題意:
定義一個二維數組:
int maze[5][5] = { 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, };
它表示一個迷宮,其中的1表示牆壁,0表示可以走的路,只能橫着走或豎着走,不能斜着走,要求編程序找出從左上角到右下角的最短路線。
思路:
很簡單的bfs迷宮問題,由於要打印路徑,得模擬隊列+pre標記。
代碼:
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n) scanf("%d",&n);
#define Scans(s) scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
ll inv(ll a,ll m) { if(a == 1) return 1; return inv(m%a,m)*(m-m/a)%m; }
int lowbit(int x) { return x & (-x); }
const int maxn = 500000 + 100;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
struct node{
int x,y;
int pre;
}que[100];
int mp[10][10];
int vis[10][10];
int dirx[] = {0,0,1,-1};
int diry[] = {1,-1,0,0};
int check(int x, int y){
if(!(0 <= x && x <= 4)) return 0;
if(!(0 <= y && y <= 4)) return 0;
if(mp[x][y] == 1) return 0;
if(vis[x][y]) return 0;
return 1;
}
void print(int ind){
if(que[ind].pre != -1){
print(que[ind].pre);
printf("(%d, %d)\n",que[ind].x,que[ind].y);
}
}
void bfs(){
int front = 0, rear = 0;
que[rear].x = 0; que[rear].y = 0; que[rear].pre = -1;
rear++;
while(front < rear){
node now = que[front];
int x = now.x; int y = now.y;
//printf("now: x:%d y:%d\n",x,y);
if(x == 4 && y == 4){
//printf("front:%d\n",front);
print(front);
return ;
}
fo(i,0,4){
if(check(x+dirx[i],y+diry[i])){
que[rear].x = x+dirx[i];
que[rear].y = y+diry[i];
que[rear].pre = front;
//printf("next: x:%d y:%d\n",que[rear].x,que[rear].y);
rear++;
}
}
front++;
}
}
int main()
{
#ifndef ONLINE_JUDGE
Fin;
#endif // ONLINE_JUDGE
me(mp,0); me(vis,0);
fo(i,0,5)
fo(j,0,5)
cin >> mp[i][j];
cout << "(0, 0)" << endl;
bfs();
return 0;
}
L題:
題意:
給你一個字符矩陣,’*‘表示沒油,’@‘表示有油,求圖中油田的個數。
思路:
其實就是求連通塊個數,直接用dfs搜一遍就行(遍歷字符數組的每一個位置,如果是'@’,油田個數加一,再dfs其連通的'@',並做上標記)。
代碼:
#include <map>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n) scanf("%d",&n);
#define Scans(s) scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 100 + 5;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
int n,m;
char mp[maxn][maxn];
int vis[maxn][maxn];
int cnt;
int check(int x, int y){
if(!(0 <= x && x <= m-1)) return 0;
if(!(0 <= y && y <= n-1)) return 0;
if(mp[x][y] != '@' || vis[x][y]) return 0;
return 1;
}
void dfs(int x, int y){
for(int i = -1; i <= 1; ++i){
for(int j = -1; j <= 1; ++j){
if(!i && !j) continue;
if(check(x+i,y+j)){
vis[x+i][y+j] = 1;
dfs(x+i,y+j);
}
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
Fin;
#endif // ONLINE_JUDGE
while(cin >> m >> n){
getchar();
//printf("m:%d n:%d\n",m,n);
if(!n && !m) break;
me(mp,0);
fo(i,0,m){
scanf("%s",mp[i]);
//printf("i:%s\n",mp[i]);
}
/*fo(i,0,m){
fo(j,0,n)
cout << mp[i][j];
cout << endl;
}*/
cnt = 0; me(vis,0);
fo(i,0,m)
fo(j,0,n){
if(mp[i][j] == '@' && !vis[i][j]){
//printf("i:%d j:%d\n",i,j);
cnt++;
vis[i][j] = 1;
dfs(i,j);
}
}
cout << cnt << endl;
}
return 0;
}
M題:
題意:
只有兩個杯子,它們的容量分別是N 毫升和M 毫升 可樂的體積爲S (S<101)毫升 (正好裝滿一瓶) ,它們三個之間可以相互倒可樂 (都是沒有刻度的,且 S==N+M,101>S>0,N>0,M>0) 。問兩個人喝能平分嗎?如果能請輸出倒可樂的最少的次數,如果不能輸出"NO"。
思路:
和H題一樣的題,只不過這裏是3個容器,所以結構體需要三個變量分別記錄三個容器剩下的可樂。這裏不需要打印,不需要模擬隊列,直接用STL中的queue就行。
代碼:
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define fi(a,n,val) fill(a,a+n,val)
#define Scand(n) scanf("%d",&n)
#define Scand2(a,b) scanf("%d%d",&a,&b)
#define Scand3(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define Scand4(a,b,c,d) scanf("%d%d%d%d",&a,&b,&c,&d)
#define Scans(s) scanf("%s",s)
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 1e4 + 50;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
struct node{
int a,b,c;
int step;
node(int aa = 0, int bb = 0, int cc = 0, int stepp = 0){
a = aa; b = bb; c = cc; step = stepp;
}
};
int s,n,m;
queue<node> que;
int vis[200][200][200];
int ans;
void bfs(){
while (!que.empty()) {
que.pop();
}
fo(i, 0, 100)
fo(j, 0, 100)
fo(k, 0, 100)
vis[i][j][k] = 0;
node startt(s, 0, 0, 0);
que.push(startt);
while (!que.empty()) {
node now = que.front();
que.pop();
int a = now.a; int b = now.b; int c = now.c; int step = now.step;
if(vis[a][b][c]) continue;
vis[a][b][c] = 1;
// printf("a:%d b:%d c:%d step:%d\n",a,b,c,step);
if((!a && b == c) || (!b && a == c) || (!c && a == b)){
ans = step;
return;
}
if(a > 0){
if(a+b > n){
node nextt(a+b-n, n, c, step+1);
que.push(nextt);
}else if(a+b < n){
node nextt(0, a+b, c, step+1);
que.push(nextt);
}
if(a+c > m){
node nextt(a+c-m, b, m, step+1);
que.push(nextt);
}else if(a+c < m){
node nextt(0, b, a+c, step+1);
que.push(nextt);
}
}
if(b > 0){
if(b+a > s){
node nextt(s, b+a-s, c, step+1);
que.push(nextt);
}else if(b+a < s){
node nextt(b+a, 0, c, step+1);
que.push(nextt);
}
if(b+c > m){
node nextt(a, b+c-m, m, step+1);
que.push(nextt);
}else if(b+c < m){
node nextt(a, 0, b+c, step+1);
que.push(nextt);
}
}
if(c > 0){
if(c+a > s){
node nextt(s, b, c+a-s, step+1);
que.push(nextt);
}else if(c < s){
node nextt(c+a, b, 0, step+1);
que.push(nextt);
}
if(c+b > n){
node nextt(a, n, c+b-n, step+1);
que.push(nextt);
}else if(c+b < n){
node nextt(a, c+b, 0, step+1);
que.push(nextt);
}
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
//Fin;
#endif // ONLINE_JUDGE
while (Scand3(s, n, m) == 3) {
if(!s && !n && !m) break;
ans = 0;
bfs();
if(ans == 0)
printf("NO\n");
else
printf("%d\n",ans);
}
return 0;
}
N題:
題意:
一張圖,上面有'@',兩個人約定到其中的一個'@'中見面,求兩人見面所花的最短時間。
思路:
可以求出兩個人到達每一個'@'所花的時間,用兩次bfs就行,然後對於每個'@',統計兩人花費的時間(即兩人分別所花時間相加),取最小值就行。
注意點:
bfs的終止條件是遍歷完所有的'@',所以事先要記錄圖中'@'的個數。
代碼:
#include <map>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n) scanf("%d",&n);
#define Scans(s) scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 110000 + 5;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
struct node{
int x,y;
int step;
node(int a, int b, int c){
x = a; y = b; step = c;
}
};
int n,m;
char mp[250][250];
int vis1[250][250]; int vis2[250][250];
queue<node> que;
int stx1,sty1,stx2,sty2;
int cnt,num;
int dirx[] = {0,0,1,-1};
int diry[] = {1,-1,0,0};
int check(int x, int y){
if(!(1 <= x && x <= n)) return 0;
if(!(1 <= y && y <= m)) return 0;
if(mp[x][y] == '#' || mp[x][y] == 'Y' || mp[x][y] == 'M') return 0;
return 1;
}
void bfs1(){
num = 0;
while(!que.empty())
que.pop();
node startt(stx1,sty1,0);
vis1[stx1][sty1] = 0;
que.push(startt);
while(!que.empty()){
node now = que.front();
que.pop();
int x = now.x; int y = now.y; int step = now.step;
if(mp[x][y] == '@'){
num++;
if(num == cnt)
return;
}
fo(i,0,4){
int xx = x + dirx[i];
int yy = y + diry[i];
if(check(xx,yy) && !vis1[xx][yy]){
node nextt(xx,yy,step+1);
vis1[xx][yy] = step+1;
que.push(nextt);
}
}
}
}
void bfs2(){
num = 0;
while(!que.empty())
que.pop();
node startt(stx2,sty2,0);
vis1[stx2][sty2] = 0;
que.push(startt);
while(!que.empty()){
node now = que.front();
que.pop();
int x = now.x; int y = now.y; int step = now.step;
if(mp[x][y] == '@'){
num++;
if(num == cnt)
return;
}
fo(i,0,4){
int xx = x + dirx[i];
int yy = y + diry[i];
if(check(xx,yy) && !vis2[xx][yy]){
node nextt(xx,yy,step+1);
vis2[xx][yy] = step+1;
que.push(nextt);
}
}
}
}
int main()
{
while(cin >> n >> m){
me(mp,0); me(vis1,0); me(vis2,0);
cnt = 0;
fo(i,1,n+1){
scanf("%s",mp[i]+1);
fo(j,1,m+1){
if(mp[i][j] == 'Y'){
stx1 = i; sty1 = j;
}
if(mp[i][j] == 'M'){
stx2 = i; sty2 = j;
}
if(mp[i][j] == '@')
cnt++;
}
}
bfs1();
bfs2();
int ans = INF;
fo(i,1,n+1){
fo(j,1,m+1){
if(mp[i][j] == '@'){
if(!vis1[i][j] || !vis2[i][j])
continue;
ans = min(ans,vis1[i][j]+vis2[i][j]);
}
}
}
cout << ans*11 << endl;
}
return 0;
}