居然发现这篇写好的题解依然躺在我桌面上…明明记得发过
Talk is cheap, Show me the code,上题目代码(以下都是基础练习题,并不包括用到像启发式搜索这种高端算法的题):
A - Red and Black
There is a rectangular room, covered with square tiles. Each tile is colored either red or black. A man is standing on a black tile. From a tile, he can move to one of four adjacent tiles. But he can’t move on red tiles, he can move only on black tiles.
Write a program to count the number of black tiles which he can reach by repeating the moves described above.
Input
The input consists of multiple data sets. A data set starts with a line containing two positive integers W and H; W and H are the numbers of tiles in the x- and y- directions, respectively. W and H are not more than 20.
There are H more lines in the data set, each of which includes W characters. Each character represents the color of a tile as follows.
‘.’ - a black tile
‘#’ - a red tile
‘@’ - a man on a black tile(appears exactly once in a data set)
Output
For each data set, your program should output a line which contains the number of tiles he can reach from the initial tile (including itself).
Sample Input
6 9
…#.
…#
…
…
…
…
…
#@…#
.#…#.
11 9
.#…
.#.#######.
.#.#…#.
.#.#.###.#.
.#.#…@#.#.
.#.#####.#.
.#…#.
.#########.
…
11 6
…#…#…#…
…#…#…#…
…#…#…###
…#…#…#@.
…#…#…#…
…#…#…#…
7 7
…#.#…
…#.#…
###.###
…@…
###.###
…#.#…
…#.#…
0 0
Sample Output
45
59
6
13
题意:以二维矩阵的形式读入一张地图,@代表起点,’.‘代表能到达的地方,’#'代表障碍,问从起点开始所能到达的地方数
BFS实现:
#include<iostream>
#include<stdio.h>
#include<cmath>
#include<string>
#include<string.h>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<list>
#include<algorithm>
using namespace std;
const int N = 1005;
const double PI = acos(-1.0);
#define P pair<int,int>
#define Q_in_out ios::sync_with_stdio(false);cin.tie(0);
#define reset(x) memset(x,0,sizeof(x))
typedef long long int ll;
int res;
int col,row;
bool check(int x,int y){
if(x>=0&&x<row&&y>=0&&y<col)
return true;
else return false;
}
struct cord
{
int x;
int y;
};
int BFS(int dx,int dy,char map[25][25]){
cord tm;
queue<cord> q;
tm.x=dx;tm.y=dy;
q.push(tm); //搜索起点入队
while (!q.empty())
{
res++;
cord t=q.front();
q.pop();
if(check(t.x,t.y-1)&&map[t.x][t.y-1]=='.') //上
{
map[t.x][t.y-1]='#'; //遍历过后的点直接处理掉
tm.x=t.x;
tm.y=t.y-1;
q.push(tm);
}
if(check(t.x,t.y+1)&&map[t.x][t.y+1]=='.') //下
{
map[t.x][t.y+1]='#';
tm.x=t.x;
tm.y=t.y+1;
q.push(tm);
}
if(check(t.x-1,t.y)&&map[t.x-1][t.y]=='.') //左
{
map[t.x-1][t.y]='#';
tm.x=t.x-1;
tm.y=t.y;
q.push(tm);
}
if(check(t.x+1,t.y)&&map[t.x+1][t.y]=='.') //右
{
map[t.x+1][t.y]='#';
tm.x=t.x+1;
tm.y=t.y;
q.push(tm);
}
}
return 0;
}
int main(){
Q_in_out
while (cin>>col>>row&&(col+row))
{
int bx,by;
char map[25][25];
for(int i=0;i<row;i++)
for(int j=0;j<col;j++)
{
cin>>map[i][j];
if(map[i][j]=='@') //记录起点
{
bx=i;
by=j;
}
}
res=0;
BFS(bx,by,map);
cout<<res<<endl;
}
return 0;
}
B - Asteroids!
You’re in space.
You want to get home.
There are asteroids.
You don’t want to hit them.
Input
Input to this problem will consist of a (non-empty) series of up to 100 data sets. Each data set will be formatted according to the following description, and there will be no blank lines separating data sets.
A single data set has 5 components:
Start line - A single line, “START N”, where 1 <= N <= 10.
Slice list - A series of N slices. Each slice is an N x N matrix representing a horizontal slice through the asteroid field. Each position in the matrix will be one of two values:
‘O’ - (the letter “oh”) Empty space
‘X’ - (upper-case) Asteroid present
Starting Position - A single line, “A B C”, denoting the <A,B,C> coordinates of your craft’s starting position. The coordinate values will be integers separated by individual spaces.
Target Position - A single line, “D E F”, denoting the <D,E,F> coordinates of your target’s position. The coordinate values will be integers separated by individual spaces.
End line - A single line, “END”
The origin of the coordinate system is <0,0,0>. Therefore, each component of each coordinate vector will be an integer between 0 and N-1, inclusive.
The first coordinate in a set indicates the column. Left column = 0.
The second coordinate in a set indicates the row. Top row = 0.
The third coordinate in a set indicates the slice. First slice = 0.
Both the Starting Position and the Target Position will be in empty space.
Output
For each data set, there will be exactly one output set, and there will be no blank lines separating output sets.
A single output set consists of a single line. If a route exists, the line will be in the format “X Y”, where X is the same as N from the corresponding input data set and Y is the least number of moves necessary to get your ship from the starting position to the target position. If there is no route from the starting position to the target position, the line will be “NO ROUTE” instead.
A move can only be in one of the six basic directions: up, down, left, right, forward, back. Phrased more precisely, a move will either increment or decrement a single component of your current position vector by 1.
Sample Input
START 1
O
0 0 0
0 0 0
END
START 3
XXX
XXX
XXX
OOO
OOO
OOO
XXX
XXX
XXX
0 0 1
2 2 1
END
START 5
OOOOO
OOOOO
OOOOO
OOOOO
OOOOO
OOOOO
OOOOO
OOOOO
OOOOO
OOOOO
XXXXX
XXXXX
XXXXX
XXXXX
XXXXX
OOOOO
OOOOO
OOOOO
OOOOO
OOOOO
OOOOO
OOOOO
OOOOO
OOOOO
OOOOO
0 0 0
4 4 4
END
Sample Output
1 0
3 4
NO ROUTE
题意:与上题大致相同,在一个三维空间里,给出每个点是O或者是X,X代表墙,给定起点和终点,求起点到终点最短路径,如果不能到达终点,输出NO ROUTE.
输入的地图是按ZYX的三位顺序输入的,处理的时候注意三维数组下标对应关系(map[z][y][x])
代码:
#include<iostream>
#include<stdio.h>
#include<cmath>
#include<string>
#include<string.h>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<list>
#include<algorithm>
using namespace std;
const int N = 1005;
const double PI = acos(-1.0);
#define P pair<int,int>
#define Q_in_out ios::sync_with_stdio(false);cin.tie(0);
#define reset(x) memset(x,0,sizeof(x))
typedef long long int ll;
int n,f;
int xbe,ybe,zbe;
int xed,yed,zed;
int direc[6][3]={{1,0,0},{-1,0,0},{0,1,0},{0,-1,0},{0,0,1},{0,0,-1}};
bool check(int x,int y,int z){
if(x>=0&&x<n&&y>=0&&y<n&&z>=0&&z<n)
return true;
else return false;
}
struct cord
{
int x;
int y;
int z;
int sum;
};
int BFS(char map[20][20][20],vector<int> &res){
if(xbe==xed&&ybe==yed&&zbe==zed){
res.push_back(0);
f=1;
return 0;
}
cord tm;
queue<cord> q;
tm.x=xbe;tm.y=ybe;tm.z=zbe;tm.sum=0;
q.push(tm); //搜索起点入队
while (!q.empty())
{
cord t=q.front();
q.pop();
for(int i=0;i<6;i++){
int tx=t.x+direc[i][0];
int ty=t.y+direc[i][1];
int tz=t.z+direc[i][2];
if(check(tx,ty,tz)&&map[tz][ty][tx]!='X'){
tm.x=tx;tm.y=ty;tm.z=tz;tm.sum=t.sum+1;
map[tz][ty][tx]='X';
if(tx==xed&&ty==yed&&tz==zed){
f=1;
res.push_back(tm.sum);
}
q.push(tm);
}
}
}
return 0;
}
int main(){
Q_in_out
string s;
while (cin>>s)
{
char map[20][20][20];
cin>>n;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
cin>>map[i][j];
cin>>xbe>>ybe>>zbe;
cin>>xed>>yed>>zed;
cin>>s;
f=0;
vector<int>res;
BFS(map,res);
sort(res.begin(),res.end());
if(f) cout<<n<<' '<<res[0]<<endl;
else cout<<"NO ROUTE"<<endl;
}
return 0;
}
C - Friend Chains
For a group of people, there is an idea that everyone is equals to or less than 6 steps away from any other person in the group, by way of introduction. So that a chain of “a friend of a friend” can be made to connect any 2 persons and it contains no more than 7 persons.
For example, if XXX is YYY’s friend and YYY is ZZZ’s friend, but XXX is not ZZZ’s friend, then there is a friend chain of length 2 between XXX and ZZZ. The length of a friend chain is one less than the number of persons in the chain.
Note that if XXX is YYY’s friend, then YYY is XXX’s friend. Give the group of people and the friend relationship between them. You want to know the minimum value k, which for any two persons in the group, there is a friend chain connecting them and the chain’s length is no more than k .
Input
There are multiple cases.
For each case, there is an integer N (2<= N <= 1000) which represents the number of people in the group.
Each of the next N lines contains a string which represents the name of one people. The string consists of alphabet letters and the length of it is no more than 10.
Then there is a number M (0<= M <= 10000) which represents the number of friend relationships in the group.
Each of the next M lines contains two names which are separated by a space ,and they are friends.
Input ends with N = 0.
Output
For each case, print the minimum value k in one line.
If the value of k is infinite, then print -1 instead.
Sample Input
3
XXX
YYY
ZZZ
2
XXX YYY
YYY ZZZ
0
Sample Output
2
题意:给定n个人,m对朋友关系,求出任意两个朋友之间最短距离,最后再求这些最短距离的最大值
BFS解决:把字符串转换成对应数字关系后利用二维vector存储朋友之间的关系。在一次BFS中用vis记录状态,遍历过的人就不再遍历,
因此两者间关系若有直接朋友关系距离即为1,也是两者的最小值,故二维数组chainl中求出的chainl[i][j]即为i->j最短距离
代码:
#include<iostream>
#include<stdio.h>
#include<cmath>
#include<string>
#include<string.h>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<list>
#include<algorithm>
using namespace std;
const int N = 1005;
const int MAX = 0x3f3f3f3f;
const double PI = acos(-1.0);
#define P pair<int,int>
#define Q_in_out ios::sync_with_stdio(false);cin.tie(0);
#define reset(x) memset(x,0,sizeof(x))
typedef long long int ll;
vector<int>frid[N];
int chainl[N][N];
int BFS(int t){
bool vis[N]={0};
vis[t]=1;
queue<int> q;
q.push(t);
while (!q.empty())
{
int tmp=q.front();
q.pop();
for(int i=0;i<frid[tmp].size();i++){
if(!vis[frid[tmp][i]]){
vis[frid[tmp][i]]=1;
chainl[t][frid[tmp][i]]=chainl[t][tmp]+1;
q.push(frid[tmp][i]);
}
}
}
return 0;
}
int main(){
Q_in_out
int n;
map<string,int>peo;
while (cin>>n&&n)
{
peo.clear();
string s1,s2;
for(int i=0;i<n;i++){
cin>>s1;
peo[s1]=i; //字符串转换数字编号方便处理
}
int m;
cin>>m; //m对朋友关系
//chainl,frid初始化
for(int i=0;i<n;i++)
{
frid[i].clear();
chainl[i][i]=0;
for(int j=i+1;j<n;j++)
{
chainl[i][j]=MAX;
chainl[j][i]=MAX;
}
}
for(int i=0;i<m;i++){
cin>>s1>>s2;
frid[peo[s1]].push_back(peo[s2]); //双向关系
frid[peo[s2]].push_back(peo[s1]);
}
for(int i=0;i<n;i++) BFS(i);
int res=0;
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++)
res=max(res,chainl[i][j]);
if(res==MAX)
cout<<-1<<endl;
else
cout<<res<<endl;
}
return 0;
}
D - Catch That Cow
Farmer John has been informed of the location of a fugitive cow and wants to catch her immediately. He starts at a point N (0 ≤ N ≤ 100,000) on a number line and the cow is at a point K (0 ≤ K ≤ 100,000) on the same number line. Farmer John has two modes of transportation: walking and teleporting.
- Walking: FJ can move from any point X to the points X - 1 or X + 1 in a single minute
- Teleporting: FJ can move from any point X to the point 2 × X in a single minute.
If the cow, unaware of its pursuit, does not move at all, how long does it take for Farmer John to retrieve it?
Input
Line 1: Two space-separated integers: N and K
Output
Line 1: The least amount of time, in minutes, it takes for Farmer John to catch the fugitive cow.
Sample Input
5 17
Sample Output
4
Hint
The fastest way for Farmer John to reach the fugitive cow is to move along the following path: 5-10-9-18-17, which takes 4 minutes.
题意:在一维空间给定农夫和牛的坐标,牛不动,农夫每分钟可以到达往前(x+1)或往后(x-1)的一步或者到达2x,问农夫最少花多久可以抓到牛
BFS,每下一步都将往前、往后或者是2x的情况处理一下,将已经遍历过的位置给排除掉,第一次出现农夫位置等于牛的位置时所花费的时间即为结果
代码:
#include<iostream>
#include<stdio.h>
#include<cmath>
#include<string>
#include<string.h>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<list>
#include<algorithm>
using namespace std;
const int N = 1e6;
const int MAX = 0x3f3f3f3f;
const double PI = acos(-1.0);
#define P pair<int,int>
#define Q_in_out ios::sync_with_stdio(false);cin.tie(0);
#define reset(x) memset(x,0,sizeof(x))
typedef long long int ll;
bool vis[N];
int ad[2]={-1,1};
struct vj
{
int loc;
int time;
};
bool check(vj x){
if(x.loc>=0&&x.loc<=100000&&vis[x.loc]!=1)
return 1;
else
return 0;
}
int BFS(int n,int k,vector<int>&res){
queue<vj>q;
vj tmp;
tmp.loc=n;tmp.time=0;
vis[tmp.loc]=1;
q.push(tmp);
while(!q.empty())
{
tmp=q.front();
q.pop();
if(tmp.loc==k) res.push_back(tmp.time);
else{
vj p;
for(int i=0;i<2;i++)
{
p.loc=tmp.loc+ad[i];
p.time=tmp.time+1;
if(check(p)){
q.push(p);
vis[p.loc]=1;
}
}
p.loc=tmp.loc*2;
p.time=tmp.time+1;
if(check(p)){
q.push(p);
vis[p.loc]=1;
}
}
}
return 0;
}
int main(){
Q_in_out
int n,k;
while (cin>>n>>k)
{
reset(vis);
vector<int> res;
BFS(n,k,res);
sort(res.begin(),res.end());
cout<<res[0]<<endl;
}
return 0;
}
E - Find The Multiple
Given a positive integer n, write a program to find out a nonzero multiple m of n whose decimal representation contains only the digits 0 and 1. You may assume that n is not greater than 200 and there is a corresponding m containing no more than 100 decimal digits.
Input
The input file may contain multiple test cases. Each line contains a value of n (1 <= n <= 200). A line containing a zero terminates the input.
Output
For each value of n in the input print a line containing the corresponding value of m. The decimal representation of m must not contain more than 100 digits. If there are multiple solutions for a given value of n, any one of them is acceptable.
Sample Input
2
6
19
0
Sample Output
10
100100100100100100
111111111111111111
题意:给定n,找n的所有整数倍的数中,全由0或者1组成的数。
解法一:
结果卡longlong+BFS不剪枝+打表…(本机上调试发现在1~200中98和198因为结果太大,时间很长,直接把这两个比较耗时的输出出来…)
代码(投机代码,谨慎阅读)
#include<iostream>
#include<stdio.h>
#include<cmath>
#include<string>
#include<string.h>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<list>
#include<algorithm>
using namespace std;
const int N = 1e7;
const int MAX = 0x3f3f3f3f;
const double PI = acos(-1.0);
#define P pair<int,int>
#define Q_in_out ios::sync_with_stdio(false);cin.tie(0);
#define reset(x) memset(x,0,sizeof(x))
typedef long long int ll;
string change(ll i){
string s1;
while(i){
s1.push_back(i%10+'0');
i/=10;
}
string s2;
for(int j=s1.size()-1;j>=0;j--){
s2.push_back(s1[j]);
}
return s2;
}
ll BFS(ll k,int n){
queue<ll>q;
q.push(k);
vis["10"]=MAX;
while(!q.empty())
{
ll i=q.front();
q.pop();
if(i%n==0) return i;
else if(i%2==0&&(i+1)%n==0) return i+1;
else
{
if(i%2==0&&9223372036854775801)
{
q.push(i+1);
}
if(i<=922337203685477580)
{
q.push(i*10);
}
}
}
return 0;
}
int main(){
Q_in_out
int n;
while (cin>>n&&n)
// while(n<=200)
{
if(n==1){
cout<<1<<endl;
// n++;
continue;
}
if(n==198){
cout<<"1111111111111111110"<<endl;
// n++;
continue;
}
if(n==99){
cout<<"111111111111111111"<<endl;
// n++;
continue;
}
vis.clear();
ll res;
res=BFS(10,n);
cout<<res<<endl;
// n++;
}
return 0;
}
然后去看了一下,发现有一个博客没用BFS,思路也巧:(原博客:https://blog.csdn.net/zx_zengxi/article/details/76325566)
代码:
#include<stdio.h>
int mod_er[1000000]; //这里必须开得足够大,才能满足能够枚举到这样的sh
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
int ans[200];
if(n==0)
return 0;
mod_er[1]=1;
int i;
for( i=2;mod_er[i-1]!=0;i++)
{
mod_er[i]=(mod_er[i/2]*10+i%2)%n; //一个个的枚举每个数的二进制,是否满足条件。
}
i--;
int k=0;
while(i)
{
int temp=i%2;
ans[k]=temp;
k++;
i=i/2;
}
for(int j=k-1;j>=0;j--)
{
printf("%d",ans[j]);
}
printf("\n");
}
}
以及DFS的做法:
代码:
#include<iostream>
#include<stdio.h>
#include<cmath>
#include<string>
#include<string.h>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<list>
#include<algorithm>
using namespace std;
const int N = 1e7;
const int MAX = 0x3f3f3f3f;
const double PI = acos(-1.0);
#define P pair<int,int>
#define Q_in_out ios::sync_with_stdio(false);cin.tie(0);
#define reset(x) memset(x,0,sizeof(x))
typedef long long int ll;
map<string,int>vis;
bool f;
int n;
int DFS(ll i,int cnt){
if(f) return 0;
if(i%n==0){
cout<<i<<endl;
f=1;
return 0;
}
if(cnt==18) return 0; //longlong最大1e18级别
DFS(i*10,cnt+1);
DFS(i*10+1,cnt+1);
return 0;
}
int main(){
Q_in_out
while (cin>>n&&n)
{
f=0;
DFS(1,0);
}
return 0;
}
F - Prime Path
The ministers of the cabinet were quite upset by the message from the Chief of Security stating that they would all have to change the four-digit room numbers on their offices.
— It is a matter of security to change such things every now and then, to keep the enemy in the dark.
— But look, I have chosen my number 1033 for good reasons. I am the Prime minister, you know!
— I know, so therefore your new number 8179 is also a prime. You will just have to paste four new digits over the four old ones on your office door.
— No, it’s not that simple. Suppose that I change the first digit to an 8, then the number will read 8033 which is not a prime!
— I see, being the prime minister you cannot stand having a non-prime number on your door even for a few seconds.
— Correct! So I must invent a scheme for going from 1033 to 8179 by a path of prime numbers where only one digit is changed from one prime to the next prime.
Now, the minister of finance, who had been eavesdropping, intervened.
— No unnecessary expenditure, please! I happen to know that the price of a digit is one pound.
— Hmm, in that case I need a computer program to minimize the cost. You don’t know some very cheap software gurus, do you?
— In fact, I do. You see, there is this programming contest going on… Help the prime minister to find the cheapest prime path between any two given four-digit primes! The first digit must be nonzero, of course. Here is a solution in the case above.
1033
1733
3733
3739
3779
8779
8179
The cost of this solution is 6 pounds. Note that the digit 1 which got pasted over in step 2 can not be reused in the last step – a new 1 must be purchased.
Input
One line with a positive number: the number of test cases (at most 100). Then for each test case, one line with two numbers separated by a blank. Both numbers are four-digit primes (without leading zeros).
Output
One line for each case, either with a number stating the minimal cost or containing the word Impossible.
Sample Input
3
1033 8179
1373 8017
1033 1033
Sample Output
6
7
0
题意:每组测试数据给定两个素数a和b,求解从素数a转化到素数b最少要几步(转化规则:每次可以将四位数中的某一位上的数字转化成其他数字,并且转化后的数字要是素数)
整个过程都是四位素数。(BFS求解)从千位开始,将每个数都先转化成0(千位是1,没有前导0),然后往上+1遍历找到所有素数入队。
代码:
#include<iostream>
#include<stdio.h>
#include<cmath>
#include<string>
#include<string.h>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<list>
#include<algorithm>
using namespace std;
const int N = 10005;
const int MAX = 0x3f3f3f3f;
const double PI = acos(-1.0);
#define P pair<int,int>
#define Q_in_out ios::sync_with_stdio(false);cin.tie(0);
#define reset(x) memset(x,0,sizeof(x))
typedef long long int ll;
bool vis[N];
bool pr[10050];
int getnum(int n,int k) //获取n的第k位数字
{
int cnt=4;
int res;
while(n)
{
res=n%10;
if(cnt==k)
return res;
n/=10;
cnt--;
}
return res;
}
int dir[4]={1000,100,10,1};
int a,b;
vector<int> res;
int is_Prime(int n){ //小于n的素数
memset(pr,0,sizeof(pr));
int i,j;
pr[0]=pr[1]=1; //0、1不是素数,所以单独处理
pr[2]=0;
for(i=2;i*i<=n;i++)
{
if(pr[i]){
continue;
}
for(j=i;j*i<=n;j++)
pr[i*j]=1;
}
return 0; //sum是素数的总个数
}
struct vj
{
int num;
int price;
};
bool check(vj x){
if(x.num>=1000&&x.num<=10000&&pr[x.num]!=1&&vis[x.num]!=1)
return 1;
else
return 0;
}
int BFS(){
queue<vj>q;
vj p;
p.num=a;p.price=0;
vis[p.num]=1;
q.push(p);
vis[a]=1;
while(!q.empty())
{
vj tmp=q.front();
q.pop();
if(tmp.num==b) res.push_back(tmp.price);
for(int i=0;i<4;i++){
int nk=getnum(tmp.num,i+1);
int newtmp;
if(i==0) //千位从1开始
newtmp=tmp.num-dir[i]*nk+1*dir[i];
else //其余位
newtmp=tmp.num-dir[i]*nk;
for(int k=0;k<=9;k++){
vj jg;
jg.price=tmp.price+1;
jg.num=newtmp+k*dir[i];
if(check(jg))
{
vis[jg.num]=1;
q.push(jg);
}
}
}
}
return 0;
}
int main(){
Q_in_out
is_Prime(10005);
int n;
cin>>n;
while(n--)
{
cin>>a>>b;
res.clear();
reset(vis);
BFS();
sort(res.begin(),res.end());
if(res.size()==0)
cout<<"Impossible"<<endl;
else
cout<<res[0]<<endl;
}
return 0;
}
PS:做完后才发现别人将目前的数中的某一位转化成0或者1时用的是sprinf和sscanf,比较省事:以下是二者的用法
#include<bits/stdc++.h>
using namespace std;
int main () {
char s[10];
sprintf(s,"%d",12345);
cout<<s<<endl;
int n;
sscanf(s,"%d",&n);
cout<<n<<endl;
s[0]='9';
sscanf(s,"%d",&n);
cout<<n<<endl;
return 0;
}
运行结果为:
12345
12345
92345
G - Pots
You are given two pots, having the volume of A and B liters respectively. The following operations can be performed:
1.FILL(i) fill the pot i (1 ≤ i ≤ 2) from the tap;
2.DROP(i) empty the pot i to the drain;
3.POUR(i,j) pour from pot i to pot j; after this operation either the pot j is full (and there may be some water left in the pot i), or the pot i is empty (and all its contents have been moved to the pot j).
Write a program to find the shortest possible sequence of these operations that will yield exactly C liters of water in one of the pots.
Input
On the first and only line are the numbers A, B, and C. These are all integers in the range from 1 to 100 and C≤max(A,B).
Output
The first line of the output must contain the length of the sequence of operations K. The following K lines must each describe one operation. If there are several sequences of minimal length, output any one of them. If the desired result can’t be achieved, the first and only line of the file must contain the word ‘impossible’.
Sample Input
3 5 4
Sample Output
6
FILL(2)
POUR(2,1)
DROP(1)
POUR(2,1)
FILL(2)
POUR(2,1)
题意:给定两个水壶的容积a,b,给定一个目标储水量c,求最短操作步数使得a或者b中的水量等于c(a,b都是从0开始),并输出操作序列,有三种操作
1.充满(i):将水壶 i 装满
2.倒掉(i):将水壶 i 清空
3.POUR(i,j):从水壶i往水壶j倒水直到j装满或i倒空为止
用一个数组记录操作的序列,输出时由于从前往后输出,递归输出即可
代码:
#include<iostream>
#include<stdio.h>
#include<cmath>
#include<string>
#include<string.h>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<list>
#include<algorithm>
using namespace std;
const int N = 10005;
const int MAX = 0x3f3f3f3f;
const double PI = acos(-1.0);
#define P pair<int,int>
#define Q_in_out ios::sync_with_stdio(false);cin.tie(0);
#define reset(x) memset(x,0,sizeof(x))
typedef long long int ll;
struct vj
{
int a,b; //a、b桶
int lasta,lastb; //上一步状态
int oper; //记录操作方法
int step;
}path[200][200];
string s[6]={"FILL(1)","FILL(2)","DROP(1)","DROP(2)","POUR(1,2)","POUR(2,1)"};
int va,vb,tc,f;
queue<vj>q;
bool vis[200][200];
int print(vj x){
if(path[x.a][x.b].a==0&&path[x.a][x.b].b==0)
return 0;
print(path[x.lasta][x.lastb]);
cout<<s[x.oper]<<endl;
return 0;
}
int push(vj x){
q.push(x);
path[x.a][x.b]=x; //保存路径
vis[x.a][x.b]=1; //当前状态已访问过
return 0;
}
int BFS(){
vj p;
p.a=0;p.b=0;p.step=0;
q.push(p);
vis[p.a][p.b]=1;
while(!q.empty())
{
vj tmp=q.front();
q.pop();
if(tmp.a==tc||tmp.b==tc){
f=1;
cout<<tmp.step<<endl;
print(tmp);
return 0;
}
p.lasta=tmp.a;p.lastb=tmp.b;p.step=tmp.step+1;
if(tmp.a!=va){ //装满a
p.a=va;
p.b=tmp.b;
p.oper=0;
if(!vis[p.a][p.b])
{
vis[p.a][p.b]=1;
push(p);
}
}
if(tmp.b!=vb){ //装满b
p.b=vb;
p.a=tmp.a;
p.oper=1;
if(!vis[p.a][p.b])
{
vis[p.a][p.b]=1;
push(p);
}
}
if(tmp.a!=0){ //倒掉a
p.a=0;
p.b=tmp.b;
p.oper=2;
if(!vis[p.a][p.b])
{
vis[p.a][p.b]=1;
push(p);
}
}
if(tmp.b!=0){ //倒掉b
p.b=0;
p.a=tmp.a;
p.oper=3;
if(!vis[p.a][p.b])
{
vis[p.a][p.b]=1;
push(p);
}
}
if(tmp.a!=0&&tmp.b!=vb){ //a->b
if(tmp.a+tmp.b>=vb)
{
p.b=vb;
p.a=tmp.a+tmp.b-vb;
}
else{
p.a=0;
p.b=tmp.a+tmp.b;
}
p.oper=4;
if(!vis[p.a][p.b])
{
vis[p.a][p.b]=1;
push(p);
}
}
if(tmp.b!=0&&tmp.a!=va){ //b->a
if(tmp.a+tmp.b>=va)
{
p.a=va;
p.b=tmp.a+tmp.b-va;
}
else{
p.b=0;
p.a=tmp.a+tmp.b;
}
p.oper=5;
if(!vis[p.a][p.b])
{
vis[p.a][p.b]=1;
push(p);
}
}
}
return 0;
}
int main(){
Q_in_out
while(cin>>va>>vb>>tc)
{
f=0;
for(int i=0;i<200;i++)
for(int j=0;j<200;j++)
{
vis[i][j]=0;
path[i][j].a=0;path[i][j].b=0;
path[i][j].step=0;path[i][j].oper=0;
path[i][j].lasta=0;
path[i][j].lastb=0;
}
while (!q.empty())
q.pop();
BFS();
if(f==0)
cout<<"impossible"<<endl;
}
return 0;
}
H - Eight
The 15-puzzle has been around for over 100 years; even if you don’t know it by that name, you’ve seen it. It is constructed with 15 sliding tiles, each with a number from 1 to 15 on it, and all packed into a 4 by 4 frame with one tile missing. Let’s call the missing tile ‘x’; the object of the puzzle is to arrange the tiles so that they are ordered as:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 x
where the only legal operation is to exchange ‘x’ with one of the tiles with which it shares an edge. As an example, the following sequence of moves solves a slightly scrambled puzzle:
1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4
5 6 7 8 5 6 7 8 5 6 7 8 5 6 7 8
9 x 10 12 9 10 x 12 9 10 11 12 9 10 11 12
13 14 11 15 13 14 11 15 13 14 x 15 13 14 15 x
r-> d-> r->
The letters in the previous row indicate which neighbor of the ‘x’ tile is swapped with the ‘x’ tile at each step; legal values are ‘r’,‘l’,‘u’ and ‘d’, for right, left, up, and down, respectively.
Not all puzzles can be solved; in 1870, a man named Sam Loyd was famous for distributing an unsolvable version of the puzzle, and
frustrating many people. In fact, all you have to do to make a regular puzzle into an unsolvable one is to swap two tiles (not counting the missing ‘x’ tile, of course).
In this problem, you will write a program for solving the less well-known 8-puzzle, composed of tiles on a three by three
arrangement.
Input
You will receive a description of a configuration of the 8 puzzle. The description is just a list of the tiles in their initial positions, with the rows listed from top to bottom, and the tiles listed from left to right within a row, where the tiles are represented by numbers 1 to 8, plus ‘x’. For example, this puzzle
1 2 3
x 4 6
7 5 8
is described by this list:
1 2 3 x 4 6 7 5 8
Output
You will print to standard output either the word ``unsolvable’’, if the puzzle has no solution, or a string consisting entirely of the letters ‘r’, ‘l’, ‘u’ and ‘d’ that describes a series of moves that produce a solution. The string should include no spaces and start at the beginning of the line.
Sample Input
2 3 4 1 5 x 7 6 8
Sample Output
ullddrurdllurdruldr
题意:八数码问题(九宫格数字华容道…),需要记录转移状态,代码少用点STL算法,开始我是用生成排列的函数去生成一个表,结果最后超时,
后面改用康托展开来计算字符串的key值,再判重,队列也是将就手写了一下,反正也不多,还比STL快。代码量有点大,最后900ms过了,内存也用掉29Mb(保存路径的方法用的数组比较大)
还有很多值得优化的地方。
代码:
#include<iostream>
#include<stdio.h>
#include<cmath>
#include<string>
#include<string.h>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<list>
#include<algorithm>
using namespace std;
const int N = 1e6;
const int MAX = 0x3f3f3f3f;
const double PI = acos(-1.0);
#define P pair<int,int>
#define Q_in_out ios::sync_with_stdio(false);cin.tie(0);
#define reset(x) memset(x,0,sizeof(x))
typedef long long int ll;
struct vj
{
int loc; //x位置
string sta; //当前状态
int last; //上一步状态
int oper; //记录操作方法
}path[370000],q[370000];
char sa[4]={'d','u','l','r'};
int f,frt,lst;
bool vis[362880];
int fac[10]={1,1,2,6,24,120,720,5040,40320,362880};
int check[9][9]={
{0,1,0,1,0,0,0,0,0},
{1,0,1,0,1,0,0,0,0},
{0,1,0,0,0,1,0,0,0},
{1,0,0,0,1,0,1,0,0},
{0,1,0,1,0,1,0,1,0},
{0,0,1,0,1,0,0,0,1},
{0,0,0,1,0,0,0,1,0},
{0,0,0,0,1,0,1,0,1},
{0,0,0,0,0,1,0,1,0}
};
int print(vj x){
if(x.last==-1) return 0;
print(path[x.last]);
cout<<sa[x.oper];
return 0;
}
int q_push(vj x){
q[lst]=x;
lst++;
return 0;
}
int q_pop(){
frt++;
return 0;
}
int cantor(string s){
int res=0;
for(int i=0;i<9;i++){
int cnt=0;
for(int j=i+1;j<9;j++)
if(s[i]>s[j])
cnt++;
res+=cnt*fac[9-i-1];
}
return res;
}
int BFS(string s,int key){
frt=lst=0;
vj p;
p.sta=s;p.oper=-1;p.last=-1;
p.loc=key;
path[cantor(p.sta)]=p;
q_push(p);
vis[cantor(p.sta)]=1;
while(frt!=lst) //模拟队列
{
vj tmp;
tmp=q[frt];
q_pop();
key=tmp.loc;
if(tmp.sta=="12345678x"){
f=1;
print(tmp);
return 0;
}
p.last=cantor(tmp.sta); //保存转移状态
if(check[key][key+3]){ //向下
string tm=tmp.sta;
p.oper=0;
p.loc=key+3;
swap(tm[key],tm[p.loc]);
int val=cantor(tm);
if(!vis[val]){
vis[val]=1;
p.sta=tm;
q_push(p);
path[cantor(p.sta)]=p;
}
}
if(check[key][key-3]){ //向上
string tm=tmp.sta;
p.oper=1;
p.loc=key-3;
swap(tm[key],tm[p.loc]);
int val=cantor(tm);
if(!vis[val]){
vis[val]=1;
p.sta=tm;
q_push(p);
path[cantor(p.sta)]=p;
}
}
if(check[key][key-1]){ //向左
string tm=tmp.sta;
p.oper=2;
p.loc=key-1;
swap(tm[key],tm[p.loc]);
int val=cantor(tm);
if(!vis[val]){
vis[val]=1;
p.sta=tm;
q_push(p);
path[cantor(p.sta)]=p;
}
}
if(check[key][key+1]){ //向右
string tm=tmp.sta;
p.oper=3;
p.loc=key+1;
swap(tm[key],tm[p.loc]);
int val=cantor(tm);
if(!vis[val]){
vis[val]=1;
p.sta=tm;
q_push(p);
path[cantor(p.sta)]=p;
}
}
}
return 0;
}
int main(){
Q_in_out
string s(9,'0');
while(cin>>s[0])
{
int loc;
if(s[0]=='x') loc=0;
for(int i=1;i<9;i++)
{
cin>>s[i];
if(s[i]=='x')
loc=i;
}
f=0;
reset(vis);
BFS(s,loc);
if(f==0)
cout<<"unsolvable";
cout<<endl;
}
return 0;
}
在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上。
你的任务是,对于给定的N,求出有多少种合法的放置方法。
Input
共有若干行,每行一个正整数N≤10,表示棋盘和皇后的数量;如果N=0,表示结束。
Output
共有若干行,每行一个正整数,表示对应输入行的皇后的不同放置数量。
Sample Input
1
8
5
0
Sample Output
1
92
10
代码:
#include<iostream>
#include<stdio.h>
#include<cmath>
#include<string>
#include<string.h>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<list>
#include<algorithm>
using namespace std;
const int N = 1e6;
const int MAX = 0x3f3f3f3f;
const double PI = acos(-1.0);
#define P pair<int,int>
#define Q_in_out ios::sync_with_stdio(false);cin.tie(0);
#define reset(x) memset(x,0,sizeof(x))
typedef long long int ll;
ll cnt;
int vis[15];
bool check(int row,int col){
for(int i=0;i<row;i++){
if(vis[i]==col||(abs(vis[i]-col)==abs(i-row))) //检测不同列、不在对角线(斜率为绝对值1)
return false;
}
return true;
}
int dfs(int r,int n){
if(r==n){
cnt++;
return 0;
}
for(int i=0;i<n;i++){
if(check(r,i))
{
vis[r]=i;
dfs(r+1,n);
}
}
return 0;
}
int main()
{
Q_in_out
ll res[15]={0};
int n;
for(int i=0;i<=10;i++)
{
reset(vis);
cnt=0;
dfs(0,i);
res[i]=cnt;
}
while(cin>>n&&n)
{
cout<<res[n]<<endl;
}
return 0;
}
BFS可以用于某些特定条件下的最短路径的求解,即不同节点间的距离/权值是一样时,当权值不同时则必须使用其他算法来求解,以下是AtCoder上的一道题,正好展示了BFS上述功能:
题目链接:https://atcoder.jp/contests/abc211/tasks/abc211_d
题目:
Problem Statement :
The Republic of AtCoder has N cities numbered 1 through N and M roads numbered 1 through M . Using Road i , you can travel from City A i to B i or vice versa in one hour. How many paths are there in which you can get from City 1 to City N as early as possible? Since the count can be enormous, print it modulo ( 1e9 + 7 ) .
题意:有1~n个节点,有m条路(无向图),问,从节点1到达节点n的最短路径有多少条,答案模1e9+7(长度为最短的路径总数)。根据题意,相邻节点间的权值都是1,故可以使用广搜来求解最短路径,在进行广搜的同时,我们需要对路径的方案数计数,在遍历某个节点的所有相邻节点时,假设当前节点是v0,我们遍历到v0的相邻节点v1,此时我们判断,若在此之前v1尚未被遍历到,我们对v1的操作是:从节点1到v1的距离等于1到v0距离加一,且到达v1的方案数等于到达v0的方案数;相反,若v1已经被前面某个节点展开时遍历过,我们需要判断此时1到v1的距离是否等于1到v0距离+1,若相等,证明这条路径也是最短路径之一,到达v1的方案数=到达v1+到达v0(加法原理)
代码:
#include <bits/stdc++.h>
using namespace std;
#define reset(x) memset(x, 0, sizeof(x))
#define Q_in_out ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
typedef long long int ll;
typedef long double ld;
typedef pair<int, int> P;
const int N = 2e5+5;
const int modp = 1e9+7;
const double pi = acos(-1.0);
const double e = 2.718281828459045;
const int inf = 0x3f3f3f3f;
// const ll inf = 2e18;
vector<int>mp[N]; //存放图
ll res[N]; //方案总数
int vis[N];//记录路径长度,也用于判断节点是否访问过
int BFS(){
queue<int>q;
q.push(1);
vis[1]=1;
res[1]=1;
while (!q.empty())
{
int tmp=q.front();
q.pop();
auto v=mp[tmp];
for(int i=0;i<v.size();i++){
if(!vis[v[i]]){
vis[v[i]]=vis[tmp]+1;
res[v[i]]=res[tmp];
q.push(v[i]);
}
else if(vis[v[i]]==vis[tmp]+1){
res[v[i]]=(res[v[i]]+res[tmp])%modp;
}
}
}
return 0;
}
int solve(){
int n,m;
cin>>n>>m;
int f,t;
for(int i=0;i<m;i++){
cin>>f>>t;
mp[f].push_back(t);
mp[t].push_back(f);
}
BFS();
cout<<res[n];
return 0;
}
int main(){
Q_in_out
int t;
t=1;
// cin>>t;
while(t--)
{
solve();
cout<<endl;
}
return 0;
}