搜索题目:
bfs+位压缩:
hdu 1429 http://acm.hdu.edu.cn/showproblem.php?pid=1429
中文题目:
思路:bfs+位压缩
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <functional> #include <numeric> #include <sstream> #include <stack> #include <map> #include <queue> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) (x) < (y) ? (x) : (y) #define Max(x, y) (x) < (y) ? (y) : (x) #define E(x) (1 << (x)) #define iabs(x) (x) < 0 ? -(x) : (x) #define OUT(x) printf("%I64d\n", x) #define lowbit(x) (x)&(-x) #define Read() freopen("din.txt", "r", stdin) #define Write() freopen("dout.txt", "w", stdout) #define M 137 #define N 22 using namespace std; const double eps = 1e-10; struct node { int x,y; int val; int msk;//一共10为来表示到达某点时所拥有的钥匙种类 bool operator < (const node &a) const { return val > a.val; } }nd; priority_queue<node>Q; int sx,sy,ex,ey; char mat[N][N]; int n,m,k; int dx[4] = {-1,0,1,0}; int dy[4] = {0,1,0,-1}; bool vt[N][N][1028];//由于是优先队列处理所以只要到达该点就是最优的 int bfs(int x,int y) { CL(vt,false); while (!Q.empty()) Q.pop(); nd.x = x; nd.y = y; nd.val = 0; nd.msk = 0; Q.push(nd); vt[x][y][nd.msk] = true; while (!Q.empty()) { node u = Q.top(); Q.pop(); for (int i = 0; i < 4; ++i) { int tx = u.x + dx[i]; int ty =u.y + dy[i]; int val = u.val + 1; int msk = u.msk; if (val >= k) continue; if (tx >= 0 && tx < n && ty >= 0 && ty < m && mat[tx][ty] != '*' && !vt[tx][ty][msk]) { nd.x = tx; nd.y = ty; nd.val = val; nd.msk = msk; if (mat[tx][ty] == '.' || mat[tx][ty] == '@') { vt[tx][ty][msk] = true; Q.push(nd); } else if (mat[tx][ty] >= 'a' && mat[tx][ty] <= 'j') { nd.msk = nd.msk | (1<<(mat[tx][ty] - 32 - 'A')); vt[tx][ty][nd.msk] = true; Q.push(nd); } else if (mat[tx][ty] >= 'A' && mat[tx][ty] <= 'J') { if (u.msk & (1<<(mat[tx][ty] - 'A'))) { vt[tx][ty][msk] = true; Q.push(nd); } } else if (mat[tx][ty] == '^') { return nd.val; } } } } return -1; } int main() { // Read(); int i,j; while (~scanf("%d%d%d",&n,&m,&k)) { for (i = 0; i < n; ++i) { scanf("%s",mat[i]); for (j = 0; j < m; ++j) { if (mat[i][j] == '@') { sx = i; sy = j; } } } printf("%d\n", bfs(sx,sy)); } return 0; }
hdu 1885 Key Task
http://acm.hdu.edu.cn/showproblem.php?pid=1885
题意:
给你一个n*m的矩形迷宫,里面有 起点* 多个出口X,墙# 还有一些门 B,Y,R,G ,只有拥有了 钥匙 b,y,r,g才能打开门然后继续往下走。求能够走出迷宫的最小步数(只要走到任意一个出口即可)
思路:
bfs+位压缩
bfs找最少步数,位压缩记录到达某个点时所拥有的钥匙
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <functional> #include <numeric> #include <sstream> #include <stack> #include <map> #include <queue> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define ll __int64 #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) (x) < (y) ? (x) : (y) #define Max(x, y) (x) < (y) ? (y) : (x) #define E(x) (1 << (x)) #define iabs(x) (x) < 0 ? -(x) : (x) #define OUT(x) printf("%I64d\n", x) #define lowbit(x) (x)&(-x) #define Read() freopen("din.txt", "r", stdin) #define Write() freopen("dout.txt", "w", stdout); #define M 20010 #define N 110 using namespace std; const int mod = 1000000007; int dx[4] = {0,1,0,-1}; int dy[4] = {1,0,-1,0}; struct node { int x,y; int ds; int msk; }nd; char mat[N][N]; bool vt[N][N][20]; int n,m; int sx,sy; int ans; int getR(char c) { if (c == 'b') return 0; if (c == 'y') return 1; if (c == 'r') return 2; return 3; } bool inmap(int x,int y) { if (x >= 0 && x < n && y >= 0 && y < m && mat[x][y] != '#') return true; return false; } bool isKey(char c) { if (c == 'b' || c == 'y' || c == 'r' || c == 'g') return true; return false; } bool isFree(char c) { if (c == '.' || c == '*') return true; return false; } bool isDoor(char c) { if (c == 'B' || c == 'Y' || c == 'R' || c == 'G') return true; return false; } int bfs(int x,int y) { nd.x = x; nd.y = y; nd.ds = 0; nd.msk = 0; queue<node>Q; Q.push(nd); CL(vt,false); vt[sx][sy][0] = true; while (!Q.empty()) { nd = Q.front(); Q.pop(); for (int i = 0; i < 4; ++i) { int tx = nd.x + dx[i]; int ty = nd.y + dy[i]; int ds = nd.ds + 1; int msk = nd.msk; if (inmap(tx,ty)) { if (mat[tx][ty] == 'X') { ans = ds; return 1; } node tmp; tmp.x = tx; tmp.y = ty; tmp.ds = ds; if (isKey(mat[tx][ty])) { msk |= (1<<(getR(mat[tx][ty]))); tmp.msk = msk; if (!vt[tx][ty][msk]) { vt[tx][ty][msk] = true; Q.push(tmp); } } else if (isFree(mat[tx][ty])) { if (!vt[tx][ty][msk]) { tmp.msk = msk; vt[tx][ty][msk] = true; Q.push(tmp); } } else if (isDoor(mat[tx][ty]) && (msk&(1<<getR(mat[tx][ty] + 32)))) { if (!vt[tx][ty][msk]) { tmp.msk = msk; vt[tx][ty][msk] = true; Q.push(tmp); } } } } } return 0; } int main() { // Read(); int i,j; while (~scanf("%d%d",&n,&m)) { if (!n && !m) break; bool flag = false; sx = sy = -1; for (i = 0; i < n; ++i) { scanf("%s",mat[i]); for (j = 0; j < m; ++j) { if (mat[i][j] == '*') { sx = i; sy = j; } if (mat[i][j] == 'X') { flag = true; } } } if (!flag || sx == -1) { printf("The poor student is trapped!\n"); continue; } ans = -1; // printf(">>>>%d %d\n",sx,sy); bfs(sx,sy); if (ans != -1) printf("Escape possible in %d steps.\n",ans); else printf("The poor student is trapped!\n"); } return 0; }
<------------------------------------------------------------------------------------------------------------->
hdu 1226 超级密码
题意:中文
思路:
首先我们要知道这样一个原理:
r%c = k%c ==> (r*p + a) = (k*p + a);
证明:
形式证明.....r=k(mod c)-> k= q*c+r -> (k*p+a)=((q*c+r)*p+a)=p*q*c+p*r+a -> (k*p+a) (mod c) = (r*p+a) (mod c)
(注:由于p*q*c中含有因子c,所以取模后=0.........)
所以我们要求组和出来的这个数的c进制数能够整除n,只要求组和出来的这个数对n取余,余数为0的情况是最小的数即可。
当我们组合出来的的数x对n取余后为y时,如果我们继续在后面添加数的(x*c + p) %n 仍然等于y而此时这个数的长度增加了,必定变大了。 所以我们只要对余数搜索,达到这个余数时的最小的数即可。 bfs来保证组和的这个数长度最短,然后从小打到枚举这m个数,就能够保证出现余数为0时即为最小。
这里有一个trick就是当n为0,时假设m个数里面有0也存在正确答案
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <functional> #include <numeric> #include <sstream> #include <stack> #include <map> #include <queue> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) (x) < (y) ? (x) : (y) #define Max(x, y) (x) < (y) ? (y) : (x) #define E(x) (1 << (x)) #define iabs(x) (x) < 0 ? -(x) : (x) #define OUT(x) printf("%I64d\n", x) #define lowbit(x) (x)&(-x) #define Read() freopen("din.txt", "r", stdin) #define Write() freopen("dout.txt", "w", stdout) #define M 137 #define N 5007 #define ll __int64 using namespace std; const double eps = 1e-10; struct node { int len; int num[507]; int rem; }nd; int vt[N]; bool ok[20]; int n,c,m; int getR(node a) { int sum = 0; for (int i = 1; i <= a.len; ++i) { sum = (sum*c%n + a.num[i])%n; } return sum; } void print(node a) { for (int i = 1; i < a.len; ++i) printf("%X",a.num[i]); printf("%X\n",a.num[a.len]); } void bfs() { CL(vt,false); queue<node>Q; for (int i = 1; i <= 16; ++i) { if (!ok[i]) continue; nd.len = 1; nd.num[nd.len] = i; nd.rem = getR(nd); if (nd.rem == 0) { print(nd); return ; } if (!vt[nd.rem]) { vt[nd.rem] = true; Q.push(nd); } } while (!Q.empty()) { nd = Q.front(); Q.pop(); for (int i = 0; i <= 16; ++i) { if (!ok[i]) continue; node tmp = nd; tmp.len = nd.len + 1; if (tmp.len > 500) break; tmp.num[tmp.len] = i; tmp.rem = getR(tmp); if (tmp.rem == 0) { print(tmp); return ; } if (!vt[tmp.rem]) { vt[tmp.rem] = true; Q.push(tmp); } } } printf("give me the bomb please\n"); } int main() { // Read(); int T,i; scanf("%d",&T); while (T--) { scanf("%d%d",&n,&c); scanf("%d",&m); CL(ok,false); int x; for (i = 0; i < m; ++i) { scanf("%x",&x); //测试用输入数据保证合法, // if (x >= c) // { // printf("NIMASHUJUBUDUI"); // } ok[x] = true; } if (n == 0) { if (ok[0]) printf("0\n"); else printf("give me the bomb please\n"); continue; } bfs(); } return 0; }
题意:
给你一个数n,求一个数m,使得m满足1:是n的倍数,2:所含不同的数字数目最少
思路:
首先我们可以根据鸽巢定理得知,存在n+1个数,使得其中肯定存在两个数的与n同余。即x%n = y%n 则abs(x - y)%n == 0 应为要使m所含不同的数字最少,所以我们假设这n+1个数形如0,a,aa,aaa,aaaa ...... aaaaaaaa(n个a) 他们存在两个数相减为n的倍数,那么这个数要么含有一个数字 例如2222 - 1111 = 1111 要么含有两个数字3333 - 11 = 3322
我们只要分别讨论即可,而且这个数的长度肯定不会超过n,模n的状态也不会超过n,当有一个时,我们只要枚举9个数字,然后枚举长度即可。当存在两个时,我们枚举这两数字,然后利用bfs保存模n的状态寻找结果求出最优即可。
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <functional> #include <numeric> #include <sstream> #include <stack> #include <map> #include <queue> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) (x) < (y) ? (x) : (y) #define Max(x, y) (x) < (y) ? (y) : (x) #define E(x) (1 << (x)) #define iabs(x) (x) < 0 ? -(x) : (x) #define OUT(x) printf("%I64d\n", x) #define lowbit(x) (x)&(-x) #define Read() freopen("data.in", "r", stdin) #define Write() freopen("d.out", "w", stdout) #define ll unsigned long long #define M 100007 #define N 65736 using namespace std; const int inf = 0x7f7f7f7f; const int mod = 1000000007; struct node { int val; int pre; }nd[N]; int n; int solve1(int a) { int s = 0; for (int i = 1; i <= n; ++i) { s = (s*10%n + a)%n; if (s == 0) return i; } return 0; } string solve2(int a[]) { for (int i = 0; i <= n; ++i) nd[i].pre = -1, nd[i].val = 0; queue<int>q; q.push(0); bool flag = true; while (!q.empty()) { int u = q.front(); q.pop(); for (int i = 0; i < 2; ++i) { if (flag && !a[i]) continue; flag = false; int tmp = (u*10%n + a[i])%n; if (tmp == 0) { string ans = ""; ans += a[i] + '0'; while (u) { ans += nd[u].val + '0'; u = nd[u].pre; } while (ans.size() != n) ans += '0'; reverse(ans.begin(),ans.end()); return ans; } if (nd[tmp].pre == -1) { nd[tmp].pre = u; nd[tmp].val = a[i]; q.push(tmp); } } } return string(n,'9'); } int main() { while (~scanf("%d",&n)) { if (!n) break; int res = n + 1; int c = 0; for (int i = 1; i < 10; ++i) { int tmp = solve1(i); if (tmp && tmp < res) res = tmp,c = i; } if (res != n + 1) { for (int i = 0; i < res; ++i) printf("%d",c); printf("\n"); } else { int a[2]; string ans = string(n,'9'); for (a[0] = 0; a[0] < 10; ++a[0]) { for (a[1] = a[0] + 1; a[1] < 10; ++a[1]) { string tmp = solve2(a); // cout<<"TMP = " << tmp <<endl; if (tmp < ans) ans = tmp; } } size_t i = 0; while (ans[i] == '0') i++; for (; i < ans.size(); ++i) printf("%c",ans[i]); printf("\n"); } } return 0; }
hdu 2821 Pusher
题意:
给你一个关系矩阵,其中'.'表示空地,'a' - 'z'表示有多少个箱子 'a' = 1, 'b' = 2...., 任选一个起点(i,j),然后上下左右找箱子推,当某一方向有箱子p个时的时候他可以移动到该点(x,y)将一个箱子移出矩阵,剩下的累加到这一方向的下一个点。 注意这里当箱子在边界上的时候不能已送, (i,j) 与 (x,y)必须满足中间至少有一个空格。
思路:
自己想了一个bfs的方法,不过写了200多行,感觉不对,然后就挂了。后来看了一下别人的,就不到100行解决了。哎,自己的思路还是不行啊。
注意我们可以一步一步的模拟的走,这样比较好处理,然后dfs往下走,我们每次移出一个箱子所以总的步数就是总的箱子个数。 然后记录每一步的操作即可。
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <functional> #include <numeric> #include <sstream> #include <stack> #include <map> #include <queue> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define ll long long #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) (x) < (y) ? (x) : (y) #define Max(x, y) (x) < (y) ? (y) : (x) #define E(x) (1 << (x)) #define iabs(x) (x) < 0 ? -(x) : (x) #define OUT(x) printf("%I64d\n", x) #define lowbit(x) (x)&(-x) #define keyTree (chd[chd[root][1]][0]) #define Read() freopen("din.txt", "r", stdin) #define Write() freopen("dout.txt", "w", stdout); #define M 35 #define N 35 using namespace std; const int inf = 0x7f7f7f7f; const int mod = 1000000007; int dx[4]={-1,1,0,0}; int dy[4]={0,0,-1,1}; char ans[20000]; int mat[N][M]; char str[N][M]; int n,m,s; bool flag; string mk = "UDLR"; bool inmap(int x,int y) { return (x >= 0 && x < n && y >= 0 && y < m); } void dfs(int x,int y,int p) { if (p >= s) { flag = true; return ; } if (flag) return ; for (int i = 0; i < 4 && !flag; ++i)//注意这里的!flag直接坑的我快死了,如果这一步没有当回溯时会影响ans,所以为了保证ans必须存在 { int tx = x + dx[i]; int ty = y + dy[i]; if (!inmap(tx,ty) || mat[tx][ty]) continue; while (inmap(tx,ty) && !mat[tx][ty]) tx += dx[i],ty += dy[i]; if (!inmap(tx + dx[i],ty + dy[i])) continue; int tmp = mat[tx][ty]; mat[tx + dx[i]][ty + dy[i]] += (tmp - 1); mat[tx][ty] = 0; ans[p] = mk[i]; dfs(tx,ty,p + 1); mat[tx + dx[i]][ty + dy[i]] -= (tmp - 1); mat[tx][ty] = tmp; } } int main() { // Read(); while (~scanf("%d%d",&m,&n)) { s = 0; for (int i = 0; i < n; ++i) { scanf("%s",str[i]); for (int j = 0; j < m; ++j) { if (str[i][j] == '.') mat[i][j] = 0; else mat[i][j] = str[i][j] - 'a' + 1; s += mat[i][j]; } } flag = false; for (int i = 0; i < n && !flag; ++i) { for (int j = 0; j < m && !flag; ++j) { if (mat[i][j] != 0) continue; dfs(i,j,0); if (flag) { printf("%d\n%d\n",i,j); for (int k = 0; k < s; ++k) printf("%c",ans[k]); printf("\n"); break; } } } } return 0; }
hdu 2128 Tempter of the Bone II
题意:
给你一个关系矩阵,其中S代表起点,D代表终点,X代表墙,1-9代表有几个炸弹,。问某人是否能够从起点到达终点。如果不能输出-1否则输出最少的时间花费
思路:
因为涉及到最小问题,还是首先考虑bfs然后我们要记录每一个状态才开始把状态搞错了,调了好久。 我们这里的状态是记录哪些墙已经被炸开了,哪些地点的炸弹已经拿过了,所以我们应该以整张图为状态,因为该图最大即为8*8 = 64 所以我们可以利用它位压缩ull来保存整张图来表示唯一状态,然后就是模拟整个走的过程。优先队列处理一下遇到目标就是最优。
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <functional> #include <numeric> #include <sstream> #include <stack> #include <map> #include <queue> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define ll long long #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) (x) < (y) ? (x) : (y) #define Max(x, y) (x) < (y) ? (y) : (x) #define E(x) (1 << (x)) #define iabs(x) (x) < 0 ? -(x) : (x) #define OUT(x) printf("%I64d\n", x) #define lowbit(x) (x)&(-x) #define keyTree (chd[chd[root][1]][0]) #define Read() freopen("din.txt", "r", stdin) #define Write() freopen("dout.txt", "w", stdout); #define ULL unsigned long long #define M 600 #define N 10 using namespace std; int dx[4]={-1,1,0,0}; int dy[4]={0,0,-1,1}; const int inf = 0x7f7f7f7f; const int mod = 1000000007; int n,m; struct node { int x,y;//点 int tm;//花费的时间 int ep;//拥有的炸弹数 ULL flag;//当前状态的整张图 node(int xi,int yi,int tmi,int epi,ULL flagi) { x = xi; y = yi; tm = tmi; ep = epi; flag = flagi; } node(){} bool operator< (const node &b) const { return tm > b.tm; } }; int sx,sy; char str[N][N]; int ans; bool flag; map<ULL,int> vt[N][N];//map来记录到达该状态的最优质 bool inmap(int x,int y) { return (x >= 0 && x < n && y >= 0 && y < m); } int bfs() { for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) { vt[i][j].clear(); } } priority_queue<node> Q; Q.push(node(sx,sy,0,0,(ULL)0)); vt[sx][sy][0] = 0; while (!Q.empty()) { node u = Q.top(); Q.pop(); // if (u.tm > vt[u.x][u.y][u.flag]) continue; if (str[u.x][u.y] == 'D') return u.tm; for (int i = 0; i < 4; ++i) { int tx = u.x + dx[i]; int ty = u.y + dy[i]; if (!inmap(tx,ty)) continue; int k = tx*m + ty; if (str[tx][ty] == 'X') { if (u.flag & ((ULL)1<<k))//已经炸开了 { map<ULL,int>::iterator it = vt[tx][ty].find(u.flag); int num = (it == vt[tx][ty].end()) ? inf:it->second; if (num > u.tm + 1) { vt[tx][ty][u.flag] = u.tm + 1; Q.push(node(tx,ty,u.tm + 1,u.ep,u.flag)); } } else//未炸开 { map<ULL,int>::iterator it = vt[tx][ty].find(u.flag|((ULL)1<<k)); int num = (it == vt[tx][ty].end()) ? inf : it->second; if (u.ep >= 1 && num > u.tm + 2) { vt[tx][ty][u.flag|((ULL)1<<k)] = u.tm + 2; Q.push(node(tx,ty,u.tm + 2,u.ep - 1,u.flag|((ULL)1<<k))); } } } else if (str[tx][ty] >= '0' && str[tx][ty] <= '9') { if (u.flag & ((ULL)1<<k))//已将取了 { map<ULL,int>::iterator it = vt[tx][ty].find(u.flag); int num = (it == vt[tx][ty].end()) ? inf : it->second; if (num > u.tm + 1) { vt[tx][ty][u.flag] = u.tm + 1; Q.push(node(tx,ty,u.tm + 1,u.ep,u.flag)); } } else { map<ULL,int>::iterator it = vt[tx][ty].find(u.flag|((ULL)1<<k)); int num = (it == vt[tx][ty].end()) ? inf : it->second; if (num > u.tm + 1) { vt[tx][ty][u.flag|((ULL)1<<k)] = u.tm + 1; Q.push(node(tx,ty,u.tm + 1,u.ep + str[tx][ty] - '0',u.flag|((ULL)1<<k))); } } } else { map<ULL,int>::iterator it = vt[tx][ty].find(u.flag); int num = (it == vt[tx][ty].end()) ? inf : it->second; if (num > u.tm + 1) { vt[tx][ty][u.flag] = u.tm + 1; Q.push(node(tx,ty,u.tm + 1,u.ep,u.flag)); } } } } return -1; } int main() { // Read(); while (~scanf("%d%d",&n,&m)) { if (!n && !m) break; for (int i = 0; i < n; ++i) { scanf("%s",str[i]); for (int j = 0; j < m; ++j) { if (str[i][j] == 'S') { sx = i,sy = j; } } } ans = bfs(); printf("%d\n",ans); } return 0; }