解题摘要

HDU 1254 推箱子

题意:图中有一个箱子,和目标点,问最少推多少步可以把箱子推到目的地。

分析:广搜+深搜,对箱子的移动进行广搜处理,广搜的过程中用深搜判断人能否到达推箱子的位置。

HDU 1254
#include <stdio.h>
#include <string.h>
#define clr(x)memset(x,0,sizeof(x))

int f[8] = {-1,1,0,0, 0,0,-1,1};

struct node
{
    int step;
    int x, y;
    int tx, ty;
}q[8000],tt,end,in,re;

int v[8][8][8][8];
int vis[8][8];
int g[8][8];
int n, m;

bool ok(int x,int y)
{
    if (x>=0 && x<n && y>=0 && y<m && g[x][y]!=1)
        return true;
    return false;
}
void dfs(int x,int y)
{
    int i;
    for (i=0; i<4; i++)
    {
        if (ok(x+f[i],y+f[i+4]) && !vis[x+f[i]][y+f[i+4]])
        {
            vis[x+f[i]][y+f[i+4]] = 1;
            dfs(x+f[i],y+f[i+4]);
        }
    }
}

int solve()
{
    scanf("%d %d",&n, &m);
    for (int i=0; i<n; i++)
        for (int j=0; j<m; j++)
        {
            scanf("%d",&g[i][j]);
            if (g[i][j] == 2)
            {
                tt.x = i;
                tt.y = j;
            }
            else if (g[i][j] == 3)
            {
                end.x = i;
                end.y = j;
            }
            else if (g[i][j] == 4)
            {
                re.x = i;
                re.y = j;
            }
        }
    clr(v);
    clr(vis);
    vis[tt.x][tt.y] = 1;
    vis[re.x][re.y] = 1;

    dfs(re.x,re.y);

    int front = 0, rear = 0;
    if (ok(tt.x+1,tt.y) && vis[tt.x+1][tt.y])
    {
        in.x = tt.x;    in.y = tt.y;
        in.tx = tt.x+1; in.ty = tt.y;
        in.step = 0;
        v[in.x][in.y][in.tx][in.ty] = 1;
        q[rear++] = in;
    }
    if (ok(tt.x-1,tt.y) && vis[tt.x-1][tt.y])
    {
        in.x = tt.x;    in.y = tt.y;
        in.tx = tt.x-1; in.ty = tt.y;
        in.step = 0;
        v[in.x][in.y][in.tx][in.ty] = 1;
        q[rear++] = in;
    }
    if (ok(tt.x,tt.y+1) && vis[tt.x][tt.y+1])
    {
        in.x = tt.x;    in.y = tt.y;
        in.tx = tt.x;   in.ty = tt.y+1;
        in.step = 0;
        v[in.x][in.y][in.tx][in.ty] = 1;
        q[rear++] = in;
    }
    if (ok(tt.x,tt.y-1) && vis[tt.x][tt.y-1])
    {
        in.x = tt.x;    in.y = tt.y;
        in.tx = tt.x;   in.ty = tt.y-1;
        in.step = 0;
        v[in.x][in.y][in.tx][in.ty] = 1;
        q[rear++] = in;
    }

    int res = -1;
    while (front < rear)
    {
        tt = q[front++];
        if (tt.x==end.x && tt.y==end.y)
        {
            if (res==-1 || tt.step < res)
                res = tt.step;
        }
        clr(vis);
        vis[tt.tx][tt.ty] = 1;
        vis[tt.x][tt.y] = 1;
        dfs(tt.tx,tt.ty);

        if (ok(tt.x+1,tt.y) && ok(tt.x-1,tt.y))
        {
            if (vis[tt.x+1][tt.y])
            {
                in.x = tt.x-1;
                in.y = tt.y;
                in.tx= tt.x;
                in.ty= tt.y;
                in.step = tt.step+1;
                if (!v[in.x][in.y][in.tx][in.ty])
                {
                    v[in.x][in.y][in.tx][in.ty] = 1;
                    q[rear++] = in;
                }
            }
            if (vis[tt.x-1][tt.y])
            {
                in.x = tt.x+1;
                in.y = tt.y;
                in.tx= tt.x;
                in.ty= tt.y;
                in.step = tt.step+1;
                if (!v[in.x][in.y][in.tx][in.ty])
                {
                    v[in.x][in.y][in.tx][in.ty] = 1;
                    q[rear++] = in;
                }
            }
        }
        if (ok(tt.x,tt.y+1) && ok(tt.x,tt.y-1))
        {
            if (vis[tt.x][tt.y+1])
            {
                in.x = tt.x;
                in.y = tt.y-1;
                in.tx= tt.x;
                in.ty= tt.y;
                in.step = tt.step+1;
                if (!v[in.x][in.y][in.tx][in.ty])
                {
                    v[in.x][in.y][in.tx][in.ty] = 1;
                    q[rear++] = in;
                }
            }
            if (vis[tt.x][tt.y-1])
            {
                in.x = tt.x;
                in.y = tt.y+1;
                in.tx= tt.x;
                in.ty= tt.y;
                in.step = tt.step+1;
                if (!v[in.x][in.y][in.tx][in.ty])
                {
                    v[in.x][in.y][in.tx][in.ty] = 1;
                    q[rear++] = in;
                }
            }
        }
    }
    return res;
}

int main()
{
    int t;
    scanf("%d",&t);
    while (t--)
    {
        printf("%d\n",solve());
    }
    return 0;
}

 

HDU 1428 漫步校园

题意:已知一个数字矩阵,例如

        1 2 3

        1 2 3

        1 2 3 

从左上角移动到右下角,有多少种路线,路线要求是:每走一步要距离终点更近。

分析:先用广搜预处理出每个点到终点的最短距离,然后进行记忆化搜索,r[x][y] 表示距离终点符合要求的路线数。

HDU 1428
#include <stdio.h>
#include <string.h>
#define INF 999999999
#define clr(x)memset(x,0,sizeof(x))
#define N 55
int g[N][N];
__int64 r[N][N];
int d[N][N];
int v[N][N];
struct node
{
    int x, y;
}q[10000],tt, in;
int f[8] = {-1,1,0,0, 0,0,-1,1};
int n;

bool ok(int x,int y)
{
    if (x>=0 && x<n && y>=0 && y<n)
        return true;
    return false;
}
int tot = 0;

__int64 dfs(int x,int y)
{
    if (r[x][y]!=-1)
        return r[x][y];
    r[x][y] = 0;
    for (int i=0; i<4; i++)
    {
        int xx =x+f[i];
        int yy =y+f[i+4];
        if (ok(xx,yy))
        {
            if (d[xx][yy]<d[x][y])
                r[x][y] += dfs(xx,yy);
        }
    }
    return r[x][y];
}

void bfs()
{
    int i, j;
    for (i=0; i<n; i++)
        for (j=0; j<n; j++)
            d[i][j] = INF;
    d[n-1][n-1] = g[n-1][n-1];

    tt.x = n-1;  tt.y = n-1;
    int front =0, rear = 0;
    q[rear++] = tt;

    while (front < rear)
    {
        tt = q[front++];
        for (i=0; i<4; i++)
        {
             in.x = tt.x+f[i];
             in.y = tt.y+f[i+4];
             if (ok(in.x,in.y))
             {
                if (d[tt.x][tt.y]+g[in.x][in.y]<d[in.x][in.y])
                {
                    d[in.x][in.y] = d[tt.x][tt.y]+g[in.x][in.y];
                    q[rear++] = in;
                }
             }
        }
    }
}

int main()
{
    int i, j;
    while (scanf("%d",&n)!=EOF)
    {
        for (i=0; i<n; i++)
            for (j=0; j<n; j++)
                scanf("%d",&g[i][j]);
        clr(r);
        bfs();

        memset(r,-1,sizeof(r));
        r[n-1][n-1] = 1;
        printf("%I64d\n",dfs(0,0));
    }
    return 0;
}

 HDU 1270 小希的数表

 题意:Gardon昨天给小希布置了一道作业,即根据一张由不超过5000的N(3<=N<=100)个正整数组成的数表两两相加得到N*(N-1)/2个和,然后再将它们排序。例如,如果数表里含有四个数1,3,4,9,那么正确答案是4,5,7,10,12,13。小希做完作业以后出去玩了一阵,可是下午回家时发现原来的那张数表不见了,好在她做出的答案还在,你能帮助她根据她的答案计算出原来的数表么?

分析:先把前四个数确定了,然后维护一个堆即可。

优先队列实现
#include <stdio.h>
#include <string.h>
#include <queue>
#include <algorithm>
using namespace std;

int b[105];
int a[5005];
int top;

struct node
{
    int x;
    const bool operator <(const struct node&a)const
    {
        return x>a.x;
    }
}tt;

int l,n;
bool ok()
{
    priority_queue<node>que;

    tt.x = b[2]+b[4];
    que.push(tt);
    tt.x = b[3]+b[4];
    que.push(tt);
        int i;
      int m = 4;
     for (i=1; i<=4; i++)
     {
        tt.x = a[i];
        que.push(tt);
     }

    int tot = 1;
    while (tot < l)
    {
        if (!que.empty() &&  que.top().x==a[tot])
        {
                tot++;
                que.pop();
        }
        else
        {
            b[++m] = a[tot]-b[1];
            for (i=1; i<m; i++)
            {
                tt.x = b[i]+b[m];
                que.push(tt);
            }
            if (m>n)
                return false;
        }
    }
    return true;
}


int main()
{
    int i, j, m;
    int flag;
    while (scanf("%d",&n),n)
    {

        l=n*(n-1)/2;

        for (i=1; i<=l; i++)
        {
            scanf("%d",&a[i]);
        }

        if (n==3)
        {
            b[1] = a[1]+a[2]-a[3];
            b[1] = b[1]/2;
            b[2] = a[1]-b[1];
            b[3] = a[2]-b[1];
            b[4] = a[4]-b[1];
            for (i=1; i<=n; i++)
                printf("%d%c",b[i],i==n?'\n':' ');
            continue;
        }

        flag = 0;
        b[1] = a[1]+a[2]-a[3];
        if (b[1]%2==0)
        {
            b[1] = b[1]/2;
            b[2] = a[1]-b[1];
            b[3] = a[2]-b[1];
            b[4] = a[4]-b[1];
            if (b[1]<=b[2] && b[2]<=b[3] && b[3]<=b[4])
            {
                if (ok())
                for (i=1; i<=n; i++)
                   printf("%d%c",b[i],i==n?'\n':' ');
            }
        }
        if ((a[1]+a[2]-a[4])%2==0)
        {
            b[1] = (a[1]+a[2]-a[4])/2;
            b[2] = a[1]-b[1];
            b[3] = a[2]-b[1];
            b[4] = a[3]-b[1];
             if (ok())
                for (i=1; i<=n; i++)
                   printf("%d%c",b[i],i==n?'\n':' ');
        }

    }
    return 0;
}

 

 HDU 1247 Hat’s Words

题意:给出一个字典,问字典里面哪些单词是由其他两个单词组成的。

分析:拆分每个字符串,分别在字典中找即可。

字典树
#include <stdio.h>
#include <string.h>
struct node
{
    int count;
    node *next[26];
}tt[2500000];
int tot;
char ss[50000][50];
void add(char *s,node *root)
{
    node *p = root;
    int i=0;
    while (s[i])
    {
        int x = s[i]-'a';
        if (p->next[x] == NULL)
        {
            p->next[x] = &tt[++tot];
            memset(tt[tot].next,NULL,sizeof(tt[tot].next));
            tt[tot].count = -1;
        }
        p = p->next[x];
        i++;
    }
    p->count = 1;
}

bool find(char *a,node *root)
{
    int x, i =0;
    node *p = root;
    while (a[i])
    {
        x = a[i]-'a';
        if (p->next[x]==NULL)
            return false;
        p = p->next[x];
        i++;
    }
    if (p->count==1)
        return true;
    return false;
}

int main()
{
    int n=0;
    int i, j;
    tot = 0;

    node *root = &tt[0];
    memset(tt[0].next,NULL,sizeof(tt[0].next));
    tt[0].count = -1;
    while (scanf("%s",ss[n])!=EOF)
    {
        add(ss[n],root);
        n++;
    }
    for (i=0; i<n; i++)
    {
        int len = strlen(ss[i]);
        char *t=ss[i];
        char st[55];
        int top = 0;
        for (j=0; j<len-1; j++)
        {
            st[top++]=ss[i][j];
            st[top] = '\0';
            if (find(st,root))
            {
                if (find(t+1+j,root))
                {
                    j=len;
                    printf("%s\n",ss[i]);
                }
            }
        }
    }

    return 0;
}

 

HDU 1263 水果

题意:给水果排序,先按产地再按名称排,并且同种水果累加。

分析:模拟水题。

View Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <map>
using namespace std;

struct node
{
    int  num;
    char c[88];
    char name[88];
}q[10000];

 bool cmp(node a,node b)
 {
     if (strcmp(a.c,b.c)!=0)
        return strcmp(a.c,b.c)<0;
    return strcmp(a.name,b.name)<0;
 }
int main()
{
    char s1[88];
    char s2[88];
    int p, m;
    int t;
    int i;
    scanf("%d",&t);
    while (t--)
    {
        scanf("%d",&m);
        for (i=0; i<m; i++)
        {
            scanf("%s %s %d",q[i].name,q[i].c,&q[i].num);
        }
        sort(q,q+m,cmp);
        int tt = 0;
        for (i=0; i<m; i++)
        {
            if (i==0 || strcmp(q[i].c,q[i-1].c)!=0)
            {

                printf("%s\n",q[i].c);
            }
            tt += q[i].num;
            if (i==m-1 || strcmp(q[i].name,q[i+1].name)!=0 || strcmp(q[i].c,q[i+1].c)!=0)
            {
                printf("   |----%s(%d)\n",q[i].name,tt);
                tt = 0;
            }
        }
        if (t)
            printf("\n");
    }
    return 0;
}

 

HLG 1618 词频统计

题意:统计一篇文章中每个词出现的次数,每个词仅包含大写和小写字母,每个词的长度至少为1,最长有可能整篇文章只有一个词。

分析:

①线性再探测+BKDR字符串哈希

BKDR_HASH
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

const int maxn = 180000;
//const int maxn = 21*1024*1024;
//char s[maxn];
//char *

int BKDRHash(char *str)
{
    int hash = 0;
    while (*str)
    {
        hash = hash*31 + (*str++);
    }
    return (hash & 0x7FFFFFFF);
}

struct node
{
    int count;
    char *s;
}h[maxn];

int num[maxn]={0};
int tot = 0;
void hashinsert(char *str)
{
    int val = BKDRHash(str)%maxn;
    while (h[val].count != 0)
    {
        if (strcmp(h[val].s,str)==0)
        {
            h[val].count++;
            break;
        }
        val = (val+1)%maxn;
    }
    if (h[val].count == 0)
    {
        int len = strlen(str);
        h[val].s = (char*)malloc(sizeof(char)*(len+1));  //多组数据时要注意释放缓存
        strcpy(h[val].s,str);
        h[val].count++;
        num[++tot] = val;
    }
}

char ss[3000000];

int main()
{
    memset(h,0,sizeof(h));
    while (scanf("%s",ss)!=EOF)
    {
        hashinsert(ss);
    }
    int i;
    for (i=1; i<=tot; i++)
        printf("%d\n",h[num[i]].count);
    return 0;
}

 ②链式+BKDR字符串哈希

链式
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

const int maxn = 120000;
const int maxc = 40000;
//const int maxn = 21*1024*1024;
//char s[maxn];
//char *

int BKDRHash(char *str)
{
    int hash = 0;
    while (*str)
    {
        hash = hash*31 + (*str++);
    }
    return (hash & 0x7FFFFFFF);
}

struct node
{
    int count;
    char *s;
    node *next;
};
node h[maxn+maxc]={0};
int tt = maxn;

int num[maxn];
int tot = 0;
void hashinsert(char *str)
{
    //int val = str[0]%3;
    //printf("%d\n",val);
    int val = BKDRHash(str)%maxn;
    if (h[val].count == 0)
    {
        int len = strlen(str);
        h[val].s = (char*)malloc(sizeof(char)*(len+1));
        strcpy(h[val].s,str);
        h[val].count++;
        num[++tot] = val;
        return;
    }
    if (strcmp(str,h[val].s)==0)
    {
        h[val].count++;
        return;
    }

    node *p = &h[val];

    while (p->next != NULL)
    {
        if (strcmp(p->next->s,str)==0)
        {
            p->next->count++;
            return;
        }
        p = p->next;
    }

    if (p->next == NULL)
    {
        p->next = &h[++tt];
        int len = strlen(str);
        p->next->s = (char*)malloc(sizeof(char)*(len+1));
        strcpy(p->next->s,str);
        p->next->count++;
        num[++tot] = tt;
    }
}

char ss[4000000];

int main()
{
   //memset(h,0,sizeof(h));
    while (scanf("%s",ss)!=EOF)
    {
        hashinsert(ss);
    }
    int i;
    for (i=1; i<=tot; i++)
        printf("%d\n",h[num[i]].count);
    return 0;
}

 

HLG 1441 Parking Ships

题意:有N个海盗,其中有一个是船长,他们都住在一个海岸线上,知道了每个海盗的房子的中心位置为x,每个海盗的船的长度是l,如果可以将他的船放在位置[a,a+l],并且满足

        a<=x<=a+l这个海盗就会高兴,首先船长会把自己的船的中心位置和自己房子的中心位置对其,船长应该如何安排船只的泊位,可以使得尽可能多的海盗高兴呢?

分析:可以采用贪心的方法,把海盗分成在船长左边和右边两个部分,若右边的的某个海盗的船要摆放的话,应该尽可能的让他的船向左放置,即满足max(lastship+p[i].len,p[i].x)

        可以将所有的长度变成2倍,这样就能避免船长的船只取一半的时候不用处理浮点数。

View Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;
const long long INF = 10000000000;
struct node
{
    long long  x;
    long long len;
}q[2][1001],c,tt;

int num[2];

bool cmp(const node a, const node b)
{
    return a.x < b.x;
}
int main()
{
    int t;
    int n;
    scanf("%d",&t);
    while (t--)
    {
        scanf("%d",&n);
        scanf("%lld %lld",&c.x,&c.len);

        num[0] = num[1] = 0;
        for (int i=0; i<n-1; i++)
        {
            scanf("%lld %lld",&tt.x,&tt.len);

            tt.len *= 2;

            if (tt.x >= c.x)
            {
                tt.x = fabs(tt.x-c.x)*2;
                if (tt.x >= c.len)
                    q[1][num[1]++] = tt;
            }
            else if (tt.x <= c.x)
            {
                tt.x = fabs(tt.x-c.x)*2;
                if (tt.x >= c.len)
                    q[0][num[0]++] = tt;
            }
        }
        sort(q[0],q[0]+num[0],cmp);
        sort(q[1],q[1]+num[1],cmp);
        int tot = 1;
        for (int j=0; j<2; j++)
        {
            long long ls = c.len;
            for (int i=0;i<num[j];tot++)
            {
                long long mins = INF;
                while (i<num[j] && q[j][i].x<mins)
                {
                    mins = min(mins,max(ls+q[j][i].len,q[j][i].x));
                    i++;
                }
                ls = mins;
            }

        }
        printf("%d\n",tot);
    }

    return 0;
}

 

HDU 1436 排列组合(二)

题意:有N个字母,每个字母的数量不定。用这N个字母组成一个长为M的串,并且规定这个串中每个字母能出现的次数。求这样的串的总数。

分析:之前处理好组合数c[][],然后d[i]表示字符串长度为i的时候用所给字符串构成的满足条件的情况数,

        递推式:  d[s[i][k]+j] += d[j]*c[m-j][s[i][k]];

View Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define clr(x)memset(x,0,sizeof(x))
const int maxn = 1001;
__int64 c[maxn][maxn],d[maxn],s[maxn][maxn];

void cc(__int64 m)
{
    int i,j;
    for (i=1; i<=m; i++)
    {
        c[i][0] = 1;
        for (j=1; j<i; j++)
            c[i][j] = c[i-1][j-1]+c[i-1][j];
        c[i][i] = 1;
    }
}
int main()
{
    int n, m;
    int i, j, k;
    while (scanf("%d %d",&n,&m)!=EOF)
    {
        cc(m);
        for (i=0; i<n; i++)
        {
            scanf("%d",&s[i][0]);
            for (j=1; j<=s[i][0]; j++)
                scanf("%d",&s[i][j]);
        }
        clr(d);
        for (i=1; i<=s[0][0]; i++)
        {
            if (s[0][i] > m)
                continue;
            d[s[0][i]] = c[m][s[0][i]];
        }
        for (i=1; i<n; i++)
        {
            if (!s[i][0])
                continue;
            for (j=m; j>=0 ; j--)
            {
                if (d[j])
                    for (k=1; k<=s[i][0] && j+s[i][k]<=m; k++)
                    {
                        if (s[i][k] > 0)
                            d[s[i][k]+j] += d[j]*c[m-j][s[i][k]];
                    }
            }
        }
        printf("%I64d\n",d[m]);
    }
    return 0;
}

 

HDU 4145 Cover The Enemy

题意:已知有两个防御塔,有N个敌人,知道了每个敌人的坐标和防御塔的坐标,现在要在两个防御塔上造大炮,要求能覆盖所有的敌人,并且造价之和为R1*R1+R2*R2

    如何设置两个炮的覆盖半径能使得造价最小。,

分析:对所有炮塔先按照和第1个防御塔的距离从小到大排序,然后一次枚举每个距离,第2个防御塔的半径就是第一个防御塔不能覆盖到的最远距离。

View Code
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
const double eps = 1e-8;

struct node
{
    int d1,d2;
    int x,y;
}t1,t2,q[100005];

double dis(node a,node b)
{
    return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
int cmp(node a,node b)
{
    return a.d2 > b.d2;
}
int main()
{
    int t;
    int n;
    int i;
    int maxdis;
    int res,tmp;
    scanf("%d",&t);
    while (t--)
    {
        scanf("%d %d %d %d",&t1.x,&t1.y,&t2.x,&t2.y);
        scanf("%d",&n);
        for (i=0; i<n; i++)
        {
            scanf("%d %d",&q[i].x,&q[i].y);
            q[i].d1 = dis(q[i],t1);
            q[i].d2 = dis(q[i],t2);
        }
        sort(q,q+n,cmp);
        res = q[0].d2;
        maxdis = 0;
        for (i=1; i<n; i++)
        {
            if (q[i-1].d1 > maxdis)
                maxdis = q[i-1].d1;
            tmp = q[i].d2+maxdis;
            if (tmp < res)
                res = tmp;
        }
        if (q[n-1].d1 > maxdis)
            maxdis = q[n-1].d1;
        if (maxdis < res)
            res = maxdis;
        printf("%d\n",res);
    }
    return 0;
}

 

posted @ 2012-12-27 07:24  about:blank  阅读(414)  评论(0编辑  收藏  举报