AC_Code:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int n,m;
bool vis[205][205];
char s[205][205];
char a[205][205];
char b[205][205];
char c[205][205];
const int Move[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
void filp(int i, int j){
if(i > 0) b[i-1][j] = (b[i-1][j] == '0' ? '1' : '0');
if(j > 0) b[i][j-1] = (b[i][j-1] == '0' ? '1' : '0');
if(i + 1 < n) b[i+1][j] = (b[i+1][j] == '0' ? '1' : '0');
if(j + 1 < m) b[i][j+1] = (b[i][j+1] == '0' ? '1' : '0');
b[i][j] = (b[i][j] == '0' ? '1' : '0');
}
int main(){
while(~scanf("%d%d",&n,&m)){
for(int i=0; i<n; ++i){
for(int j=0; j<m; ++j){
getchar();
scanf("%c",&a[i][j]);
}
}
int minn = 0x3f3f3f3f;
for(int i=0; i<(1<<m); ++i){
memset(c,0,sizeof(c));
memcpy(b,a,sizeof(b));
int cnt = 0;
for(int j=m-1; j>=0; --j){
if((i>>(m-1-j)&1) == 1){
c[0][j] = '1';
filp(0,j);
cnt += 1;
}
else{
c[0][j] = '0';
}
}
for(int ii=1; ii<n; ++ii){
for(int jj=0; jj<m; ++jj){
if(b[ii-1][jj] == '1'){
filp(ii,jj);
c[ii][jj] = '1';
cnt += 1;
}
else c[ii][jj] = '0';
}
}
bool flag = true;
for(int kk=0; kk<m; ++kk){
if(b[n-1][kk] == '1'){
flag = false;
break;
}
}
if(!flag) continue;
if(cnt < minn){
minn = cnt;
memcpy(s,c,sizeof(s));
}
}
if(minn == 0x3f3f3f3f) cout << "IMPOSSIBLE\n";
else{
for(int i=0; i<n; ++i){
for(int j=0; j<m; ++j){
if(j != m-1)
cout << s[i][j] << " ";
else cout<< s[i][j] << endl;
}
}
}
}
}
D - Find The Multiple
D - Find The Multiple
题意:
给定一个正整数n,请编写一个程序来寻找n的一个非零的倍数m,这个m应当在十进制表示时每一位上只包含0或者1。
题解:
这道题一开始以为位数会很大,然后看到别人开了long long就过了…由于输出任意一个满足即可,从1开始跑bfs即可。
AC_Code:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SZ(X) ((int)(X).size())
#define ALL(X) (X).begin(), (X).end()
#define REP(I, N) for (int I = 0; I < (N); ++I)
#define REPP(I, A, B) for (int I = (A); I < (B); ++I)
#define FOR(I, A, B) for (int I = (A); I <= (B); ++I)
#define FORS(I, S) for (int I = 0; S[I]; ++I)
#define RS(X) scanf("%s", (X))
#define SORT_UNIQUE(c) (sort(c.begin(),c.end()), c.resize(distance(c.begin(),unique(c.begin(),c.end()))))
#define GET_POS(c,x) (lower_bound(c.begin(),c.end(),x)-c.begin())
#define CASET int ___T; scanf("%d", &___T); for(int cs=1;cs<=___T;cs++)
#define MP make_pair
#define PB push_back
#define MS0(X) memset((X), 0, sizeof((X)))
#define MS1(X) memset((X), -1, sizeof((X)))
#define LEN(X) strlen(X)
#define F first
#define S second
using namespace std;
typedef long long ll,LL;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int,int> PII;
typedef vector<int> VI;
typedef vector<LL> VL;
typedef vector<PII> VPII;
typedef pair<LL,LL> PLL;
typedef vector<PLL> VPLL;
void R() {}
#ifdef HOME
#define DEBUG(...) {printf("# ");printf(__VA_ARGS__);puts("");}
#else
#define DEBUG(...)
#endif
const int maxn = 1555510;
ll a[maxn],b[maxn];
int mod = 1e9+7;
ll n;
struct node{
ll s;
};
node c;
queue<node>q;
void bfs(){
q.push(c);
node d;
while(!q.empty()){
d = q.front();
if(d.s % n == 0){
cout << d.s << endl;
return;
}
q.pop();
node e = d;
e.s = d.s * 10;
q.push(e);
e.s = d.s * 10 + 1;
q.push(e);
}
}
int main(){
while(~scanf("%lld",&n) && n){
c.s = 1LL;
while(!q.empty()) q.pop();
bfs();
}
}
E - Prime Path
E - Prime Path
题意:
给你两个四位的素数a,b。a可以改变某一位上的数字变成c,但只有当c也是四位的素数时才能进行这种改变。询问计算a最少经过多少次上述变换才能变成b。
题解:
这道题做得还是挺坎坷的,先将1000到10000的素数先打表,可O(1)判断素数,接下来对每一位进行bfs即可。
AC_Code:
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
struct node{
char s[10];
int step;
};
node a,b;
queue<node>q;
int minn;
bool v[10005];
int m[10005];
void init(){
a.step = 0;b.step = 0;
minn = 0x3f3f3f3f;
memset(m,0,sizeof(m));
while(!q.empty()) q.pop();
}
int ex_change(char s[]){
int num = 0, cnt = 3;
for(int i=0; i<strlen(s); ++i){
num += (s[i]-'0') * int(pow(10,cnt--));
}
return num;
}
bool judge(char a1[], char a2[]){
int len = strlen(a1);
if(len != strlen(a2)) return false;
for(int i=0; i<len; ++i){
if(a1[i] != a2[i]) return false;
}
return true;
}
void bfs(){
q.push(a);
node c;
while(!q.empty()){
c = q.front();
q.pop();
m[ex_change(c.s)] += 1;
if(!strcmp(b.s,c.s)){
printf("%d\n",c.step);
return;
}
for(int i=0; i<4; ++i){
for(int j=0; j<10; ++j){
node new_c = c;
new_c.s[i] = '0' + j;
if(new_c.s[0] == '0') continue;
if(!v[ex_change(new_c.s)] || m[ex_change(new_c.s)]) continue;
m[ex_change(new_c.s)] += 1;
new_c.step = c.step + 1;
q.push(new_c);
}
}
}
printf("Impossible\n");
}
int main(){
int t;
for(int i=1000; i<10000; ++i){
bool flag = true;
for(int j=2; j*j<=i; ++j){
if(i%j==0){
flag = false;
break;
}
}
if(flag) v[i] = true;
}
scanf("%d",&t);
while(t--){
init();
scanf("%s",a.s);
scanf("%s",b.s);
bfs();
}
}
F - Shuffle’m Up
F - Shuffle’m Up
题意:
给你三个字符串,问第一个字符串和第二个字符串是否可以通过变换,组合成第三个字符串,变换规则如下:假设s1=12345,s2=67890,变换后的序列 s=6172839405,s1=61728,s2=39405
题解:
map水过,如果在变换过程中组合成的字符串在前面出现过,那么它将陷入一个“死循环”,永远组合不成目标字符串。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SZ(X) ((int)(X).size())
#define ALL(X) (X).begin(), (X).end()
#define REP(I, N) for (int I = 0; I < (N); ++I)
#define REPP(I, A, B) for (int I = (A); I < (B); ++I)
#define FOR(I, A, B) for (int I = (A); I <= (B); ++I)
#define FORS(I, S) for (int I = 0; S[I]; ++I)
#define RS(X) scanf("%s", (X))
#define SORT_UNIQUE(c) (sort(c.begin(),c.end()), c.resize(distance(c.begin(),unique(c.begin(),c.end()))))
#define GET_POS(c,x) (lower_bound(c.begin(),c.end(),x)-c.begin())
#define CASET int ___T; scanf("%d", &___T); for(int cs=1;cs<=___T;cs++)
#define MP make_pair
#define PB push_back
#define MS0(X) memset((X), 0, sizeof((X)))
#define MS1(X) memset((X), -1, sizeof((X)))
#define LEN(X) strlen(X)
#define F first
#define S second
using namespace std;
typedef long long ll,LL;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int,int> PII;
typedef vector<int> VI;
typedef vector<LL> VL;
typedef vector<PII> VPII;
typedef pair<LL,LL> PLL;
typedef vector<PLL> VPLL;
void R() {}
#ifdef HOME
#define DEBUG(...) {printf("# ");printf(__VA_ARGS__);puts("");}
#else
#define DEBUG(...)
#endif
const int maxn = 10;
int mod = 1e9+7;
int n,num;
struct node{
};
queue<node>q;
int startX, startY;
const int Move[4][2] = {{0,1},{0,-1},{-1,0},{1,0}};
bool vis[maxn][maxn];
map<string, int>m;
int fath[100100];
int len;
node a;
string s1;
string s2;
string s3;
string s;
int main(){
int t;
while(~scanf("%d",&t)){
int cnt = 0;
while(t--){
m.clear();
cin >> len;
cin >> s1 >> s2 >> s3;
int num = 1;
while(1){
s = "";
for(int i=0; i<len; ++i){
s += s2[i];
s += s1[i];
}
if(s == s3){
cout << ++cnt << " " << num << endl;
break;
}
num += 1;
if(m[s]){
cout << ++cnt << " " << -1 << endl;
break;
}
m[s] += 1;
for(int i=0; i<len; ++i) s1[i] = s[i];
for(int i=0; i<len; ++i) s2[i] = s[i+len];
}
}
}
}
G - Pots
G - Pots
题意:
给定两个容器,问最少需要多少次操作可以使得任意一个杯子中体积为C,如果不存在输出-1.
题解:
裸bfs,在结构体中用father记录父代,最终递归输出即可。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int a,b,c;
void choose(int x){
if(x == 1) puts("FILL(1)");
else if(x == 2) puts("FILL(2)");
else if(x == 3) puts("POUR(1,2)");
else if(x == 4) puts("POUR(2,1)");
else if(x == 5) puts("DROP(1)");
else if(x == 6) puts("DROP(2)");
}
bool vis[105][105];
struct node
{
int left;
int right;
int father;
int ope;
};
node q[20000];
int head = 0;
int tail = 0;
int times = 0;
void print(node k){
times += 1;
if(k.father != -1){
print(q[k.father]);
}
if(k.father == -1) cout << --times << endl;
choose(k.ope);
}
void init(){
memset(vis,0,sizeof(vis));
memset(q,0,sizeof(q));
head = 0;
tail = 0;
times = 0;
}
void bfs(){
q[tail].left = 0; q[tail].right = 0; q[tail].father = -1;
tail += 1;
vis[0][0] = 1;
while(head < tail){
if(q[head].left == c || q[head].right == c){
print(q[head]);
return;
}
if(q[head].left != a){
q[tail].left = a;
q[tail].right = q[head].right;
if(!vis[q[tail].left][q[tail].right]){
vis[q[tail].left][q[tail].right] = 1;
q[tail].father = head;
q[tail].ope = 1;
tail += 1;
}
}
if(q[head].right != b){
q[tail].left = q[head].left;
q[tail].right = b;
if(!vis[q[tail].left][q[tail].right]){
vis[q[tail].left][q[tail].right] = 1;
q[tail].father = head;
q[tail].ope = 2;
tail += 1;
}
}
if(q[head].right != b){
int need = b - q[head].right;
if(q[head].left < need){
q[tail].left = 0;
q[tail].right = q[head].right + q[head].left;
if(!vis[q[tail].left][q[tail].right]){
vis[q[tail].left][q[tail].right] = 1;
q[tail].father = head;
q[tail].ope = 3;
tail += 1;
}
}
else{
q[tail].left = q[head].left - need;
q[tail].right = b;
if(!vis[q[tail].left][q[tail].right]){
vis[q[tail].left][q[tail].right] = 1;
q[tail].father = head;
q[tail].ope = 3;
tail += 1;
}
}
}
if(q[head].left != a){
int need = a - q[head].left;
if(q[head].right < need){
q[tail].right = 0;
q[tail].left = q[head].left + q[head].right;
if(!vis[q[tail].left][q[tail].right]){
vis[q[tail].left][q[tail].right] = 1;
q[tail].father = head;
q[tail].ope = 4;
tail += 1;
}
}
else{
q[tail].left = a;
q[tail].right = q[head].right - need;
if(!vis[q[tail].left][q[tail].right]){
vis[q[tail].left][q[tail].right] = 1;
q[tail].father = head;
q[tail].ope = 4;
tail += 1;
}
}
}
if(q[head].left != 0){
q[tail].left = 0;
q[tail].right = q[head].right;
if(!vis[q[tail].left][q[tail].right]){
vis[q[tail].left][q[tail].right] = 1;
q[tail].father = head;
q[tail].ope = 5;
tail += 1;
}
}
if(q[head].right != 0){
q[tail].right = 0;
q[tail].left = q[head].left;
if(!vis[q[tail].left][q[tail].right]){
vis[q[tail].left][q[tail].right] = 1;
q[tail].father = head;
q[tail].ope = 6;
tail += 1;
}
}
head += 1;
}
puts("impossible");
}
int main(){
while(cin >> a >> b >> c){
init();
bfs();
}
}
H - Oil Deposits
H - Oil Deposits
题意:
在n*m的图中’@'表示该处藏有石油,如果这些蕴藏石油的小方格相邻(横向相邻,纵向相邻,还有对角相邻),那么它们被认为是同一油藏的一部分,问这些石油组成多少部分。
题解:
裸bfs。
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 222;
char s[maxn][maxn];
bool vis[maxn][maxn];
int step[maxn][maxn][maxn];
int num = 0;
int n,m,h;
int startX, startY, startZ, endX, endY, endZ;
const int Move[8][2] = {{0,1},{0,-1},{-1,0},{1,0},{1,1},{1,-1},{-1,1},{-1,-1}};
int minn;
struct node{
int x;
int y;
int num;
};
queue<node>q;
node st;
node End;
void init(){
while(!q.empty()) q.pop();
memset(vis,false,sizeof(vis));
}
inline bool check(int x, int y){
if(x >= 0 && x < n && y >= 0 && y < m && !vis[x][y] && s[x][y] == '@') return true;
return false;
}
void bfs(){
node cur;
cur.x = startX;
cur.y = startY;
q.push(cur);
vis[cur.x][cur.y] = 1;
while(!q.empty()){
cur = q.front();
q.pop();
for(int i=0; i<8; ++i){
int tx = cur.x + Move[i][0];
int ty = cur.y + Move[i][1];
if(check(tx,ty)){
vis[tx][ty] = 1;
node k;
k.x = tx; k.y = ty;
q.push(k);
}
}
}
}
int main(){
while(~scanf("%d%d",&n,&m)){
if(m == 0) break;
init();
int sum = 0;
for(int i=0; i<n; ++i){
getchar();
for(int j=0; j<m; ++j){
scanf("%c",&s[i][j]);
}
}
for(int i=0; i<n; ++i){
for(int j=0; j<m; ++j){
if(s[i][j] == '@' && !vis[i][j]){
startX = i;
startY = j;
bfs();
sum += 1;
}
}
}
cout << sum << endl;
}
}
I - 非常可乐
I - 非常可乐
题意:
有一杯可乐和两个杯子,询问最少的次数满足两个被子中的可乐平分。
题解:
可乐体积为奇数显然不满足,然后bfs遍历所有情况即可。
#include
#include
#include
using namespace std;
int n,m,s;
bool vis[109][109][109];
struct node{
int left;
int mid;
int right;
int step;
};
queue<node>q;
node cnt;
void init(){
memset(vis,0,sizeof(vis));
while(!q.empty()) q.pop();
}
void bfs(){
q.push(cnt);
while(!q.empty()){
node k = q.front();
q.pop();
if((k.left == n && k.mid == n) || (k.left == n && k.right == n) || (k.mid == n && k.right == n)){
cout << k.step << endl;
return;
}
node new_k = k;
if(k.left != 0){
new_k.left -= (m - new_k.mid);
new_k.mid = m;
new_k.step += 1;
if(!vis[new_k.left][new_k.mid][new_k.right])
q.push(new_k);
vis[new_k.left][new_k.mid][new_k.right] = 1;
}
new_k = k;
if(k.left != 0){
new_k.left -= (s - new_k.right);
new_k.right = s;
new_k.step += 1;
if(!vis[new_k.left][new_k.mid][new_k.right])
q.push(new_k);
vis[new_k.left][new_k.mid][new_k.right] = 1;
}
new_k = k;
if(k.mid != 0){
new_k.mid = 0;
new_k.left += k.mid;
new_k.step += 1;
if(!vis[new_k.left][new_k.mid][new_k.right])
q.push(new_k);
vis[new_k.left][new_k.mid][new_k.right] = 1;
}
new_k = k;
if(k.mid != 0){
if(k.mid < s - k.right) new_k.mid = 0, new_k.right += k.mid;
else new_k.mid -= (s - k.right), new_k.right = s;
new_k.step += 1;
if(!vis[new_k.left][new_k.mid][new_k.right])
q.push(new_k);
vis[new_k.left][new_k.mid][new_k.right] = 1;
}
new_k = k;
if(k.right != 0){
new_k.left += k.right;
new_k.right = 0;
new_k.step += 1;
if(!vis[new_k.left][new_k.mid][new_k.right])
q.push(new_k);
vis[new_k.left][new_k.mid][new_k.right] = 1;
}
new_k = k;
if(k.right != 0){
if(k.right < m - k.mid) new_k.mid += k.right, new_k.right = 0;
else new_k.mid = m, new_k.right -= (m - k.mid);
new_k.step += 1;
if(!vis[new_k.left][new_k.mid][new_k.right])
q.push(new_k);
vis[new_k.left][new_k.mid][new_k.right] = 1;
}
}
puts("NO");
}
int main(){
while(~scanf("%d%d%d",&n,&m,&s)){
if(n == 0) break;
if(n % 2 != 0){
puts("NO");
continue;
}
init();
cnt.left = n; cnt.mid = 0; cnt.right = 0;
n /= 2;
bfs();
}
}
J - Find a way
J - Find a way
题意:
两个人出发,有多个KFC,询问两个人到同一个KFC的最短路径。
题解:
对两个点跑两次bfs,然后用两个二维数组记录两个人到每个KFC的距离,维护距离最小值即可。
AC_Code:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int n,m;
bool vis[205][205];
char s[205][205];
int a[205][205];
int b[205][205];
const int Move[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
struct node
{
int x;
int y;
int step;
node(){}
node(int xx, int yy, int st){
x = xx;
y = yy;
step = st;
}
};
queue<node>q;
node p1,p2;
void init(){
memset(vis,0,sizeof(vis));
while(!q.empty()) q.pop();
}
void bfs1(node k){
q.push(k);
while(!q.empty()){
node new_k = q.front();
q.pop();
for(int i=0; i<4; ++i){
int tx = new_k.x + Move[i][0];
int ty = new_k.y + Move[i][1];
if(tx >= 0 && tx < n && ty >= 0 && ty < m && !vis[tx][ty] && s[tx][ty] != '#'){
if(s[tx][ty] == '@'){
a[tx][ty] = new_k.step + 1;
}
vis[tx][ty] = 1;
node ppp = node(tx,ty,new_k.step+1);
q.push(ppp);
}
}
}
}
void bfs2(node k){
q.push(k);
while(!q.empty()){
node new_k = q.front();
q.pop();
for(int i=0; i<4; ++i){
int tx = new_k.x + Move[i][0];
int ty = new_k.y + Move[i][1];
if(tx >= 0 && tx < n && ty >= 0 && ty < m && !vis[tx][ty] && s[tx][ty] != '#'){
if(s[tx][ty] == '@'){
b[tx][ty] = new_k.step + 1;
}
vis[tx][ty] = 1;
node ppp = node(tx,ty,new_k.step+1);
q.push(ppp);
}
}
}
}
int main(){
while(~scanf("%d%d",&n,&m)){
init();
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
for(int i=0; i<n; ++i){
scanf("%s",s[i]);
}
for(int i=0; i<n; ++i){
for(int j=0; j<m; ++j){
if(s[i][j] == 'Y'){
p1 = node(i,j,0);
vis[i][j] = 1;
}
if(s[i][j] == 'M'){
p2 = node(i,j,0);
vis[i][j] = 1;
}
}
}
bfs1(p1);
init();
for(int i=0; i<n; ++i){
for(int j=0; j<m; ++j){
if(s[i][j] == 'Y'){
p1 = node(i,j,0);
vis[i][j] = 1;
}
if(s[i][j] == 'M'){
p2 = node(i,j,0);
vis[i][j] = 1;
}
}
}
bfs2(p2);
int minn = 0x3f3f3f3f;
for(int i=0; i<n; ++i){
for(int j=0; j<m; ++j){
if(s[i][j] == '@' && vis[i][j]){
minn = min(minn, a[i][j] + b[i][j]);
}
}
}
cout << minn * 11 << endl;
}
}
K - 马走日
K - 马走日
题意:
给定n*m大小的棋盘,以及马的初始位置(x,y),要求不能重复经过棋盘上的同一个点,计算马可以有多少途径遍历棋盘上的所有点。
题解:
裸dfs。
#include
#include
#include
#include
using namespace std;
int n,m;
int startX, startY;
int num;
bool vis[20][20];
int Move[9][2] = {{0,0},{-2,-1},{-2,1},{-1,-2},{-1,2},{1,-2},{1,2},{2,1},{2,-1}};
void init(){
num = 0;
memset(vis,false,sizeof(vis));
}
bool kiss(int x, int y){
if(x >= 0 && x < n && y >= 0 && y < m && !vis[x][y]) return true;
return false;
}
void dfs(int x, int y, int step){
if(step == n * m){
num++;
return;
}
for(int i=0; i<9; ++i){
int tx = x + Move[i][0];
int ty = y + Move[i][1];
if(kiss(tx,ty)){
vis[tx][ty] = true;
dfs(tx,ty,step+1);
vis[tx][ty] = false;
}
}
}
int main(){
int t;
while(~scanf("%d",&t)){
while(t--){
init();
scanf("%d%d%d%d",&n,&m,&startX,&startY);
vis[startX][startY] = true;
dfs(startX,startY,1);
printf("%d\n",num);
}
}
}
L - 海贼王之伟大航路
L - 海贼王之伟大航路
没思路,待补。
M - 迷宫问题
M - 迷宫问题
题意:
输出一个二维迷宫从左上角到右下角最短路径。
题解:
由于要输出路径,因此不能用queue 弹出,手写队列(由于数据小,不会出现爆栈情况)记录路径。
AC_Code:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SZ(X) ((int)(X).size())
#define ALL(X) (X).begin(), (X).end()
#define REP(I, N) for (int I = 0; I < (N); ++I)
#define REPP(I, A, B) for (int I = (A); I < (B); ++I)
#define FOR(I, A, B) for (int I = (A); I <= (B); ++I)
#define FORS(I, S) for (int I = 0; S[I]; ++I)
#define RS(X) scanf("%s", (X))
#define SORT_UNIQUE(c) (sort(c.begin(),c.end()), c.resize(distance(c.begin(),unique(c.begin(),c.end()))))
#define GET_POS(c,x) (lower_bound(c.begin(),c.end(),x)-c.begin())
#define CASET int ___T; scanf("%d", &___T); for(int cs=1;cs<=___T;cs++)
#define MP make_pair
#define PB push_back
#define MS0(X) memset((X), 0, sizeof((X)))
#define MS1(X) memset((X), -1, sizeof((X)))
#define LEN(X) strlen(X)
#define F first
#define S second
using namespace std;
typedef long long ll,LL;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int,int> PII;
typedef vector<int> VI;
typedef vector<LL> VL;
typedef vector<PII> VPII;
typedef pair<LL,LL> PLL;
typedef vector<PLL> VPLL;
void R() {}
#ifdef HOME
#define DEBUG(...) {printf("# ");printf(__VA_ARGS__);puts("");}
#else
#define DEBUG(...)
#endif
const int maxn = 10;
ll a[maxn],b[maxn];
int mod = 1e9+7;
int n,m,num;
struct node{
int x;
int y;
int father;
};
node q[20000];
char s[maxn][maxn];
int startX, startY;
const int Move[4][2] = {{0,1},{0,-1},{-1,0},{1,0}};
bool vis[maxn][maxn];
int fath[100100];
void print(int x){
if(q[x].father != -1){
print(q[x].father);
}
printf("(%d, %d)\n",q[x].x,q[x].y);
}
void bfs(){
int head = 0, tail = 0;
q[tail].x = 0; q[tail].y = 0; q[tail].father = -1;
vis[0][0] = 1;
tail += 1;
while(head < tail){
bool flag = false;
for(int i=0; i<4; ++i){
int tx = q[head].x + Move[i][0];
int ty = q[head].y + Move[i][1];
if(tx >= 0 && tx < 5 && ty >= 0 && ty < 5 && !vis[tx][ty] && s[tx][ty] == '0'){
q[tail].x = tx; q[tail].y = ty; q[tail].father = head;
vis[tx][ty] += 1;
tail += 1;
}
if(tx == 4 && ty == 4){
tail -= 1;
print(tail);
}
}
head += 1;
}
}
int main(){
for(int i=0; i<5; ++i){
for(int j=0; j<5; ++j){
scanf("%s",&s[i][j]);
}
getchar();
}
bfs();
}
N - 鸣人和佐助
N - 鸣人和佐助
题意:
鸣人可以往上下左右四个方向移动,每移动一个距离需要花费1个单位时间,打败大蛇丸的手下不需要时间。鸣人有一定数量的查克拉,每一个单位的查克拉可以打败一个大蛇丸的手下。如果鸣人查克拉消耗完了,则只可以走到没有大蛇丸手下的位置,不可以再移动到有大蛇丸手下的位置。佐助在此期间不移动,大蛇丸的手下也不移动。请问,鸣人要追上佐助最少需要花费多少时间?
题解:
单独跑bfs找到的路径不一定是时间最短的路径,因此使用优先队列,考虑每个队列中鸣人的时间和所需的查克拉,如果时间相等,则优先跑查克拉小的点,否则跑时间小的点,当所需查克拉大于手里有的查克拉时退出。
AC_Code:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 222;
char s[maxn][maxn];
bool vis[maxn][maxn];
int num = 0;
int n,m,h;
int startX, startY, startZ, endX, endY, endZ;
const int Move[4][2] = {{0,1},{0,-1},{-1,0},{1,0}};
int minn;
struct node{
int x;
int y;
int num;
int step;
friend bool operator <(const node A, const node B){
if(A.step == B.step) return A.num > B.num;
return A.step > B.step;
}
O - 红与黑
O - 红与黑
题意:
一个人从起点‘@’出发,问他可以到多少个’.’,此人不能通过’#’.
题解:
裸dfs。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SZ(X) ((int)(X).size())
#define ALL(X) (X).begin(), (X).end()
#define REP(I, N) for (int I = 0; I < (N); ++I)
#define REPP(I, A, B) for (int I = (A); I < (B); ++I)
#define FOR(I, A, B) for (int I = (A); I <= (B); ++I)
#define FORS(I, S) for (int I = 0; S[I]; ++I)
#define RS(X) scanf("%s", (X))
#define SORT_UNIQUE(c) (sort(c.begin(),c.end()), c.resize(distance(c.begin(),unique(c.begin(),c.end()))))
#define GET_POS(c,x) (lower_bound(c.begin(),c.end(),x)-c.begin())
#define CASET int ___T; scanf("%d", &___T); for(int cs=1;cs<=___T;cs++)
#define MP make_pair
#define PB push_back
#define MS0(X) memset((X), 0, sizeof((X)))
#define MS1(X) memset((X), -1, sizeof((X)))
#define LEN(X) strlen(X)
#define F first
#define S second
using namespace std;
typedef long long ll,LL;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int,int> PII;
typedef vector<int> VI;
typedef vector<LL> VL;
typedef vector<PII> VPII;
typedef pair<LL,LL> PLL;
typedef vector<PLL> VPLL;
void R() {}
#ifdef HOME
#define DEBUG(...) {printf("# ");printf(__VA_ARGS__);puts("");}
#else
#define DEBUG(...)
#endif
const int maxn = 30;
ll a[maxn],b[maxn];
int mod = 1e9+7;
int n,m,num;
struct node{
ll s1;
};
node c;
queue<node>q;
char s[maxn][maxn];
int startX, startY;
const int Move[4][2] = {{0,1},{0,-1},{-1,0},{1,0}};
bool vis[maxn][maxn];
void dfs(int x, int y, int step){
num++;
for(int i=0; i<4; ++i){
int tx = x + Move[i][0];
int ty = y + Move[i][1];
if(tx >= 0 && tx < n && ty >= 0 && ty < m && !vis[tx][ty] && s[tx][ty] == '.'){
vis[tx][ty] = 1;
dfs(tx,ty,step+1);
}
}
}
int main(){
while(~scanf("%d%d",&m,&n) && m && n){
num = 0;
memset(vis,false,sizeof(vis));
for(int i=0; i<n; ++i){
scanf("%s",s[i]);
}
for(int i=0; i<n; ++i){
for(int j=0; j<m; ++j){
if(s[i][j] == '@'){
startX = i;
startY = j;
break;
}
}
}
vis[startX][startY] = 1;
dfs(startX, startY, 1);
cout << num << endl;
}
}
P - 棋盘问题
P - 棋盘问题
题意:
在一个给定形状的棋,要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,求摆放k个棋子的所有可行的摆放方案C。
题解:
从上往下遍历每个’#’,由于不能放在同一行,因此接下来的棋子应该往该行下面放,这样便能枚举所有的情况。
AC_Code:
#include
using namespace std;
char s[10][10];
bool vis[10];
int n,k,num;
void init(){
num = 0;
memset(vis,0,sizeof(vis));
}
void dfs(int x, int y, int sum){
if(sum == k){
num += 1;
return;
}
for(int i=x+1; i<n; ++i){
for(int j=0; j<n; ++j){
if(s[i][j] == '#' && !vis[j]){
vis[j] = 1;
dfs(i,j,sum+1);
vis[j] = 0;
}
}
}
}
int main(){
while(~scanf("%d%d",&n,&k)){
if(n == -1) break;
init();
for(int i=0; i<n; ++i){
scanf("%s",s[i]);
}
dfs(-1,-1,0);
cout << num << endl;
}
}
Q - 拯救行动
Q - 拯救行动
题意:
骑士可以向上、下、左、右四个方向移动,每移动一个位置需要1个单位时间,杀死一个守卫需要花费额外的1个单位时间。计算拯救行动成功需要花费最短时间。
由于直接裸bfs找到的路径并不一定是花费时间最少的路径,因此采用优先队列处理,重载重新根据每个点所需的时间进行排序,然后bfs即可。
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 222;
char s[maxn][maxn];
bool vis[maxn][maxn];
int step[maxn][maxn][maxn];
int num = 0;
int n,m,h;
int startX, startY, startZ, endX, endY, endZ;
const int Move[4][2] = {{0,1},{0,-1},{-1,0},{1,0}};
int minn;
struct node{
int x;
int y;
int num;
friend bool operator <(const node A,const node B){
return A.num > B.num;
}
};
priority_queue<node>q;
node st;
node End;
void init(){
while(!q.empty()) q.pop();
memset(vis,false,sizeof(vis));
st.x = 0; st.y = 0; st.num = 0;
End.x = 0; End.y = 0; End.num = 0;
}
inline bool check(int x, int y){
if(x >= 0 && x < n && y >= 0 && y < m && !vis[x][y] && s[x][y] != '#') return true;
return false;
}
void bfs(){
node cur;
q.push(st);
vis[st.x][st.y] = 1;
int minn = 0x3f3f3f3f;
while(!q.empty()){
cur = q.top();
q.pop();
for(int i=0; i<4; ++i){
int tx = cur.x + Move[i][0];
int ty = cur.y + Move[i][1];
if(s[tx][ty] == 'a'){
minn = min(minn, cur.num+1);
}
if(check(tx,ty)){
vis[tx][ty] = 1;
node k;
k.x = tx; k.y = ty; k.num = cur.num;
if(s[tx][ty] == '@') k.num += 1;
else if(s[tx][ty] == 'x') k.num += 2;
q.push(k);
}
}
}
if(minn == 0x3f3f3f3f)
printf("Impossible\n");
else cout << minn << endl;
}
int main(){
int t;
while(~scanf("%d",&t)){
while(t--){
init();
scanf("%d%d",&n,&m);
for(int i=0; i<n; ++i){
getchar();
for(int j=0; j<m; ++j){
scanf("%c",&s[i][j]);
if(s[i][j] == 'r'){
startX = i;
startY = j;
}
if(s[i][j] == 'a'){
endX = i;
endY = j;
}
}
}
st.x = startX; st.y = startY; st.num = 0;
bfs();
}
}
}
R - Saving Tang Monk
R - Saving Tang Monk
题意:
要从K走到T处,并且要先收集k把钥匙,收集钥匙顺序递增,即拿到第一把钥匙才能拿到第二把钥匙,还有不超过五条蛇‘S’(之前没看到这里只有五条不会做),每次打蛇要+1s,蛇死了再路过是不用打的。
题意:
只有五条蛇,给蛇编号然后状压记录打的蛇的状态。剩下的就BFS。(还不是很理解)
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int n,m;
bool vis[205][205][10];
char s[205][205];
char mp[205][205];
const int Move[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
struct node
{
int x;
int y;
int step;
int key;
int snake;
node(){}
node(int new_x, int new_y, int new_step, int new_key, int new_snake){
x = new_x;
y = new_y;
step = new_step;
key = new_key;
snake = new_snake;
}
friend bool operator < (const node P, const node Q){
return P.step > Q.step;
}
};
priority_queue<node>q;
node Start;
node End;
int ans = 1;
void init(){
while(!q.empty()) q.pop();
memset(vis,0,sizeof(vis));
}
bool judge(int x, int y){
if(x >= 0 && x < n && y >= 0 && y < n && s[x][y] != '#') return true;
return false;
}
bool judge_s(node p, int x){
if(p.snake & (1 << x)) return false;
return true;
}
void bfs(){
q.push(Start);
vis[Start.x][Start.y][0] = 1;
while(!q.empty()){
node k = q.top();
q.pop();
for(int i=0; i<4; ++i){
int tx = k.x + Move[i][0];
int ty = k.y + Move[i][1];
if(judge(tx,ty) && !vis[tx][ty][k.key]){
if(k.key == m && s[tx][ty] == 'T'){
cout << k.step + 1 << endl;
return;
}
else if(s[tx][ty] == k.key + '0' + 1){
vis[tx][ty][k.key] = 1;
node new_k = node(tx,ty,k.step+1,k.key+1,k.snake);
q.push(new_k);
}
else if(s[tx][ty] >= 0 && s[tx][ty] <= 5 && judge_s(k,s[tx][ty])){
vis[tx][ty][k.key] = 1;
node new_k = node(tx,ty,k.step+2,k.key,k.snake|(1<<s[tx][ty]));
q.push(new_k);
}
else{
vis[tx][ty][k.key] = 1;
node new_k = node(tx,ty,k.step+1,k.key,k.snake);
q.push(new_k);
}
}
}
}
printf("impossible\n");
}
int main(){
while(~scanf("%d%d",&n,&m)){
init();
if(n == 0) break;
for(int i=0; i<n; ++i){
scanf("%s",s[i]);
}
int cnt = 0;
for(int i=0; i<n; ++i){
for(int j=0; j<n; ++j){
if(s[i][j] == 'K'){
Start = node(i,j,0,0,0);
}
if(s[i][j] == 'T'){
End = node(i,j,0,m,0);
}
if(s[i][j] == 'S'){
s[i][j] = cnt++;
}
}
}
bfs();
}
}
S - Fire Game
S - Fire Game
题意:
两个熊孩子在n*m的平地上放火玩,#表示草,两个熊孩子分别选一个#格子点火,火可以向上向下向左向右在有草的格子蔓延,点火的地方时间为0,蔓延至下一格的时间依次加一。求烧完所有的草需要的最少时间。如不能烧完输出-1。(两个火同时点)
题解:
AC_Code:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MST(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int MAXN = 15;
const int INF = 0x3f3f3f3f;
char mp[MAXN][MAXN];
bool vis[MAXN][MAXN];
int dir[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
struct node {
int x, y, cnt;
node(int _x, int _y, int _c) {
x = _x;
y = _y;
cnt = _c;
}
node() {}
} ;
vector <node> grass;
int n, m, t, res;
void init() {
res = INF;
grass.clear();
MST(mp, 0);
}
void bfs(node s1, node s2) {
MST(vis, false);
queue <node> q;
q.push(s1);
q.push(s2);
vis[s1.x][s1.y] = vis[s2.x][s2.y] = true;
node now, next;
int sum = 0;
while (!q.empty()) {
now = q.front();
q.pop();
if (mp[now.x][now.y] == '#') sum++;
if (sum == grass.size()) {
res = min(res, now.cnt);
}
for (int i = 0; i < 4; i++) {
next.x = now.x + dir[i][1];
next.y = now.y + dir[i][0];
next.cnt = now.cnt + 1;
if (next.x < 0 || next.y < 0 || next.x >= n || next.y >= m) continue;
if (vis[next.x][next.y] || mp[next.x][next.y] == '.') continue;
vis[next.x][next.y] = true;
q.push(next);
}
}
}
int main() {
ios::sync_with_stdio(false);
cin >> t;
for (int tt = 1; tt <= t; tt++) {
init();
cin >> n >> m;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++) {
cin >> mp[i][j];
if (mp[i][j] == '#') {
node tmpnd;
tmpnd.x = i;
tmpnd.y = j;
tmpnd.cnt = 0;
grass.push_back(tmpnd);
}
}
for (int i = 0; i < grass.size(); i++)
for (int j = i; j < grass.size(); j++)
bfs(grass[i], grass[j]);
cout << "Case " << tt << ": ";
if (res != INF) cout << res << endl;
else cout << "-1" << endl;
}
}
T - Fire!
T - Fire!
题意:
一个人从J出发,同时火从F处开始燃烧,每1s火往上下左右扩散,人可以往上下左右移动一格,‘#’表示墙壁,逃离边界即可避免火灾,询问是否可以安全逃离。(PS:本题坑:F不止一处,也可能没F(数据并无体现。。。))
题解:
特判没有火的情况(裸bfs),然后考虑有火的情况,每一秒先处理火先烧的区域,vis数组标记,然后人再移动,bfs即可。
AC_Code:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 1222;
string s[maxn];
bool vis[maxn][maxn];
int num = 0;
int n,m,h;
int startX, startY, startZ, endX, endY, endZ;
const int Move[4][2] = {{0,1},{0,-1},{-1,0},{1,0}};
int minn;
struct node{
int x;
int y;
int num;
};
queue<node>q;
queue<node>new_q;
queue<node>f;
queue<node>new_f;
node st;
node End;
void init(){
while(!q.empty()) q.pop();
while(!f.empty()) f.pop();
while(!new_f.empty()) new_f.pop();
while(!new_q.empty()) new_q.pop();
memset(vis,false,sizeof(vis));
}
inline bool check(int x, int y){
if(x >= 0 && x < n && y >= 0 && y < m && !vis[x][y] && s[x][y] != '#') return true;
return false;
}
void bfs(){
node cur;
node fire;
q.push(st);
if(f.size() == 0){
while(!q.empty()){
node test = q.front();
q.pop();
for(int i=0; i<4; ++i){
int tx = test.x + Move[i][0];
int ty = test.y + Move[i][1];
if(tx < 0 || tx >= n || ty < 0 || ty >= m){
cout << test.num + 1 << endl;
return;
}
if(!vis[tx][ty] && s[tx][ty] != '#'){
vis[tx][ty] = 1;
node k;
k.x = tx; k.y = ty; k.num = test.num + 1;
q.push(k);
}
}
}
}
while(!q.empty() || !f.empty()){
while(!f.empty()){
fire = f.front();
f.pop();
for(int i=0; i<4; ++i){
int tx = fire.x + Move[i][0];
int ty = fire.y + Move[i][1];
if(check(tx,ty)){
vis[tx][ty] = 1;
node k;
k.x = tx; k.y = ty; k.num = 0;
new_f.push(k);
}
}
}
while(!new_f.empty()){
f.push(new_f.front());
new_f.pop();
}
while(!q.empty()){
cur = q.front();
q.pop();
for(int i=0; i<4; ++i){
int tx = cur.x + Move[i][0];
int ty = cur.y + Move[i][1];
if(tx < 0 || tx >= n || ty < 0 || ty >= m){
cout << cur.num + 1 << endl;
return;
}
if(!vis[tx][ty] && s[tx][ty] != '#'){
vis[tx][ty] = 1;
node k;
k.x = tx; k.y = ty; k.num = cur.num + 1;
new_q.push(k);
}
}
}
while(!new_q.empty()){
q.push(new_q.front());
new_q.pop();
}
}
printf("IMPOSSIBLE\n");
}
int main(){
int t;
int ans = 1;
cin >> n >> m;
init();
for(int i=0; i<n; ++i){
cin >> s[i];
}
for(int i=0; i<n; ++i){
for(int j=0; j<m; ++j){
if(s[i][j] == 'J'){
startX = i;
startY = j;
}
if(s[i][j] == 'F'){
End.x = i; End.y = j;
vis[i][j] = 1;
f.push(End);
}
}
}
st.x = startX; st.y = startY; st.num = 0;
vis[startX][startY] = 1;
bfs();
}
U - Cops and Robbers
U - Cops and Robbers
题意:
一帮盗贼从‘B’处出发,为了不让盗贼逃走,需建立围墙进行防卫,小写字母表示可以建立围墙,最后一行的输入表示对应的字母处建立围墙的金钱,’.'处盗贼可以通过但是不能建立围墙,询问最少需要多少金钱可防止盗贼逃走。
题解:
(待补)