叉姐的魔法训练(第三课)---- 火球术入门

-----------------------------------------

一 双向贪心

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;
}



-----------------------------------------

-----------------------------------------

-----------------------------------------

-----------------------------------------

posted on 2013-10-03 14:33  电子幼体  阅读(436)  评论(0编辑  收藏  举报

导航