-----------------------------------------
一 双向贪心
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;
}
-----------------------------------------
-----------------------------------------
-----------------------------------------
-----------------------------------------