叉姐的魔法训练(第三课)---- 火球术入门
-----------------------------------------
一 双向贪心
POJ 3040 Allowance
从大到小贪心选取一次,从小到大选取一次。
缺少证明。。。
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int maxn=41; const int INF=0x3f3f3f3f; typedef long long LL; typedef pair<int,int> PII; PII a[maxn]; int use[maxn]; int n,c; int main() { while (~scanf("%d%d",&n,&c)){ for (int i=1;i<=n;i++){ scanf("%d%d",&a[i].first,&a[i].second); } sort(a+1,a+n+1); int ans=0; while (1){ memset(use,0,sizeof(use)); int rest=c; for (int i=n;i>=1;i--){ int tmp=min(rest/a[i].first,a[i].second); rest-=tmp*a[i].first; use[i]=tmp; } if (rest){ for (int i=1;i<=n;i++){ if (a[i].second&&a[i].first>=rest){ use[i]++; rest=0; break; } } } if (rest) break; int Min=INF; for (int i=1;i<=n;i++){ if (use[i]){ Min=min(Min,a[i].second/use[i]); } } ans+=Min; for (int i=1;i<=n;i++){ if (use[i]){ a[i].second-=use[i]*Min; } } } printf("%d\n",ans); } return 0; }
-----------------------------------------
二 分层搜索
POJ 3182 The Grove
找到最上排最左边的障碍,向右虚拟一个楼梯,将图分为两层即可广搜。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <cstdlib> #include <queue> using namespace std; const int maxn=51; const int INF=0x3f3f3f3f; const int direct[8][2]={{0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1}}; struct Point{ int x,y,c,s; Point(){} Point(int x,int y,int c,int s){ this->x=x; this->y=y; this->c=c; this->s=s; } }; int n,m; bool vis[maxn][maxn][2]; char map[maxn][maxn]; int sx,sy; int dx,dy; queue<Point>que; void init(){ memset(vis,0,sizeof(vis)); while (!que.empty()) que.pop(); } void canNotMove(){ for (int i=1;i<=n;i++){ for (int j=1;j<=m;j++){ if (map[i][j]=='X'){ dx=i; dy=j; return; } } } } bool input(){ if (~scanf("%d%d",&n,&m)){ for (int i=1;i<=n;i++) scanf("%s",map[i]+1); return true; } return false; } void findStart(){ for (int i=1;i<=n;i++){ for (int j=1;j<=m;j++){ if (map[i][j]=='*'){ sx=i; sy=j; return; } } } } bool check(Point p){ if (p.x>=1&&p.x<=n&&p.y>=1&&p.y<=m) return true; return false; } bool online(Point p){ if (p.x==dx&&p.y>=dy) return true; return false; } int bfs(){ vis[sx][sy][0]=true; que.push(Point(sx,sy,0,0)); while (!que.empty()){ Point frt=que.front(); que.pop(); for (int i=0;i<8;i++){ Point p=frt; p.x+=direct[i][0]; p.y+=direct[i][1]; p.s+=1; if (!check(p)||map[p.x][p.y]=='X') continue; if (p.x==frt.x+1&&!online(frt)&&online(p)) continue; if (p.x==frt.x-1&&online(frt)&&!online(p)) p.c=1; if (vis[p.x][p.y][p.c]) continue; if (p.x==sx&&p.y==sy&&p.c==1) return p.s; vis[p.x][p.y][p.c]=true; que.push(p); } } return -1; } int main() { while (input()){ init(); canNotMove(); findStart(); printf("%d\n",bfs()); } return 0; }
-----------------------------------------
三 模拟神题
POJ 2434 Waves
题解和代码摘自网络
要注意同一个波源发出的波反弹回来的时候是可以叠加或者相消的。
每个石头可以分为两个波,一个高峰波,一个低谷波。
每个波可以分为很多个水平方向的波。
每个水平方向的波有三种情况,起始点的位置:
1. 位于 B1 左边
2. 位于 B1,B2 中间
3. 位于 B2 右边
#include <cstdio> #include <cmath> #include <algorithm> #include <iostream> #include <cstring> using namespace std; int map[9][9]; int rx[5], ry[5], rt[5], bk1, bk2; int vali (int x) { if (x >= -4 && x <= 4) return 1; else return 0; } void radix (int *row, int y, int t, int rec) { int i, phi, tm, x, dir; int u1, u2, d1, d2; phi = (t - rt[rec]) - abs(y - ry[rec]); if (rx[rec] < bk1) { u1 = rx[rec] - phi; u2 = rx[rec] + phi; d1 = rx[rec] - phi + 2; d2 = rx[rec] + phi - 2; if (u2 >= bk1) u2 = bk1 + bk1 - 1 - u2; if (d2 >= bk1) d2 = bk1 + bk1 - 1 - d2; if (phi >= 0 && vali(u1)) row[u1 + 4]++; if (phi >= 1 && vali(u2)) row[u2 + 4]++; if (phi >= 2 && vali(d1)) row[d1 + 4]--; if (phi >= 3 && vali(d2)) row[d2 + 4]--; return; } else if (rx[rec] > bk2) { u1 = rx[rec] - phi; u2 = rx[rec] + phi; d1 = rx[rec] - phi + 2; d2 = rx[rec] + phi - 2; if (u1 <= bk2) u1 = bk2 + bk2 + 1 - u1; if (d1 <= bk2) d1 = bk2 + bk2 + 1 - d1; if (phi >= 0 && vali(u1)) row[u1 + 4]++; if (phi >= 1 && vali(u2)) row[u2 + 4]++; if (phi >= 2 && vali(d1)) row[d1 + 4]--; if (phi >= 3 && vali(d2)) row[d2 + 4]--; return; } else { u1 = rx[rec] - phi; u2 = rx[rec] + phi; d1 = rx[rec] - phi + 2; d2 = rx[rec] + phi - 2; while (1) { if (u1 <= bk1) u1 = bk1 + bk1 + 1 - u1; else break; if (u1 >= bk2) u1 = bk2 + bk2 - 1 - u1; else break; } while (1) { if (d1 <= bk1) d1 = bk1 + bk1 + 1 - d1; else break; if (d1 >= bk2) d1 = bk2 + bk2 - 1 - d1; else break; } while (1) { if (u2 >= bk2) u2 = bk2 + bk2 - 1 - u2; else break; if (u2 <= bk1) u2 = bk1 + bk1 + 1 - u2; else break; } while (1) { if (d2 >= bk2) d2 = bk2 + bk2 - 1 - d2; else break; if (d2 <= bk1) d2 = bk1 + bk1 + 1 - d2; else break; } if (phi >= 0 && vali(u1)) row[u1 + 4]++; if (phi >= 1 && vali(u2)) row[u2 + 4]++; if (phi >= 2 && vali(d1)) row[d1 + 4]--; if (phi >= 3 && vali(d2)) row[d2 + 4]--; return; } } int main () { int p, time, t, i, j; scanf("%d %d %d %d", &p, &bk1, &bk2, &time); if (bk1 > bk2) { t = bk1; bk1 = bk2; bk2 = t; } for (i = 0; i < p; i++) scanf("%d %d %d", &rx[i], &ry[i], &rt[i]); memset(map, 0, sizeof(map)); for (i = 0; i < p; i++) { for (j = -4; j <= 4; j++) radix(map[j + 4], j, time, i); } for (j = 8; j >= 0; j--) { for (i = 0; i < 9; i++) { if (i - 4 == bk1 || i - 4 == bk2) printf("X"); else if (map[j][i] < 0) printf("o"); else if (map[j][i] > 0) printf("*"); else printf("-"); } printf("\n"); } return 0; }
-----------------------------------------
-----------------------------------------
-----------------------------------------
-----------------------------------------