您的位置:首页 > 其它

2014上海全国邀请赛(hdu 5090 - 5099)dp+线段树+拓扑排序+bfs(状态压缩)

2015-07-10 10:12 429 查看
Game with Pearls

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 1431 Accepted Submission(s): 527

Problem Description

Tom and Jerry are playing a game with tubes and pearls. The rule of the game is:

1) Tom and Jerry come up together with a number K.

2) Tom provides N tubes. Within each tube, there are several pearls. The number of pearls in each tube is at least 1 and at most N.

3) Jerry puts some more pearls into each tube. The number of pearls put into each tube has to be either 0 or a positive multiple of K. After that Jerry organizes these tubes in the order that the first tube has exact one pearl, the 2nd tube has exact 2 pearls, …, the Nth tube has exact N pearls.

4) If Jerry succeeds, he wins the game, otherwise Tom wins.

Write a program to determine who wins the game according to a given N, K and initial number of pearls in each tube. If Tom wins the game, output “Tom”, otherwise, output “Jerry”.

Input

The first line contains an integer M (M<=500), then M games follow. For each game, the first line contains 2 integers, N and K (1 <= N <= 100, 1 <= K <= N), and the second line contains N integers presenting the number of pearls in each tube.

Output

For each game, output a line containing either “Tom” or “Jerry”.

Sample Input

2

5 1

1 2 3 4 5

6 2

1 2 3 4 5 5

Sample Output

Jerry

Tom

题意:有n个盒子,每个盒子初始有1-n个球,现在要在盒子里添加k的倍数个球,使得最后盒子排序后,第一个盒子有1个球,第n个盒子有n个球

思路:暴力,1-n每个数字是由谁得来的,只要有一个就可以,如果有多个,那么如果满足题意条件,剩下的也必然能转化成其他的

[code]#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=510;
int a[maxn];
int N,K;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&N,&K);
        memset(a,0,sizeof(a));
        for(int i=1;i<=N;i++)
        {
            int x;
            scanf("%d",&x);
            a[x]++;
        }
        bool flag=true;
        for(int i=1;i<=N;i++)
        {
            bool flag1=false;
            for(int j=0;i-K*j>=0;j++)
            {
                if(a[i-K*j])
                {
                    flag1=true;
                    a[i-j*K]--;
                    break;
                }
            }
            if(!flag1){flag=false;break;}
        }
        if(flag)printf("Jerry\n");
        else printf("Tom\n");
    }
    return 0;
}


Beam Cannon

Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 644 Accepted Submission(s): 234

Problem Description

Recently, the γ galaxies broke out Star Wars. Each planet is warring for resources. In the Star Wars, Planet X is under attack by other planets. Now, a large wave of enemy spaceships is approaching. There is a very large Beam Cannon on the Planet X, and it is very powerful, which can destroy all the spaceships in its attack range in a second. However, it takes a long time to fill the energy of the Beam Cannon after each shot. So, you should make sure each shot can destroy the enemy spaceships as many as possible.

To simplify the problem, the Beam Cannon can shot at any area in the space, and the attack area is rectangular. The rectangle parallels to the coordinate axes and cannot rotate. It can only move horizontally or vertically. The enemy spaceship in the space can be considered as a point projected to the attack plane. If the point is in the rectangular attack area of the Beam Cannon(including border), the spaceship will be destroyed.

Input

Input contains multiple test cases. Each test case contains three integers N(1<=N<=10000, the number of enemy spaceships), W(1<=W<=40000, the width of the Beam Cannon’s attack area), H(1<=H<=40000, the height of the Beam Cannon’s attack area) in the first line, and then N lines follow. Each line contains two integers x,y (-20000<=x,y<=20000, the coordinates of an enemy spaceship).

A test case starting with a negative integer terminates the input and this test case should not to be processed.

Output

Output the maximum number of enemy spaceships the Beam Cannon can destroy in a single shot for each case.

Sample Input

2 3 4

0 1

1 0

3 1 1

-1 0

0 1

1 0

-1

Sample Output

2

2

题意:有n个星星,一个W*H的框,问最多能框住多少星星

思路:线段树扫描线,将每个点抽象成两条线段,我是按y轴方向扫的,这样做的原因是每个点的影响范围有限,见下图。




图中A点可以影响到的矩形是(x,x+W)范围内的,A点抽象成了1,-1这两条线,也就是说明,他纵向能影响到的是这个范围。

[code]#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=40010;
const int BIT=20000;
int N,W,H;
struct Segment
{
    int l,r,h,t;
    Segment()=default;
    Segment(int a,int b,int c,int d):l(a),r(b),h(c),t(d){}
    bool operator<(const Segment &a)const
    {
        return h<a.h;
    }
}s[maxn];
struct IntervalTree
{
    int sum[maxn<<2];
    int setv[maxn<<2];
    void build(int o,int l,int r)
    {
        sum[o]=setv[o]=0;
        if(l==r)return ;
        int mid=(l+r)>>1;
        build(o<<1,l,mid);
        build(o<<1|1,mid+1,r);
    }
    void  pushdown(int o)
    {
        if(setv[o])
        {
            setv[o<<1]+=setv[o];
            setv[o<<1|1]+=setv[o];
            sum[o<<1]+=setv[o];
            sum[o<<1|1]+=setv[o];
            setv[o]=0;
        }
    }
    void pushup(int o)
    {
        sum[o]=max(sum[o<<1],sum[o<<1|1]);
    }
    void update(int o,int l,int r,int q1,int q2,int x)
    {
        if(q1<=l&&r<=q2)
        {
            sum[o]+=x;
            setv[o]+=x;
            return ;
        }
        pushdown(o);
        int mid=(l+r)>>1;
        if(q1<=mid)update(o<<1,l,mid,q1,q2,x);
        if(q2>mid)update(o<<1|1,mid+1,r,q1,q2,x);
        pushup(o);
    }
}tree;
int main()
{
    while(scanf("%d",&N)!=EOF,N>0)
    {
        scanf("%d%d",&W,&H);
        int num=0;
        for(int i=0;i<N;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            x+=BIT,y+=BIT;
            int lx=(x+W>40000?40000:x+W);
            s[num++]=Segment(x,lx,y,1);
            s[num++]=Segment(x,lx,y+H,-1);
        }
        int ans=0;
        sort(s,s+num);
        tree.build(1,0,40000);
        for(int i=0;i<num;i++)
        {
            tree.update(1,0,40000,s[i].l,s[i].r,s[i].t);
            ans=max(ans,tree.sum[1]);
        }
        printf("%d\n",ans);
    }
    return 0;
}


Seam Carving

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 797 Accepted Submission(s): 323

Problem Description

Fish likes to take photo with his friends. Several days ago, he found that some pictures of him were damaged. The trouble is that there are some seams across the pictures. So he tried to repair these pictures. He scanned these pictures and stored them in his computer. He knew it is an effective way to carve the seams of the images He only knew that there is optical energy in every pixel. He learns the following principle of seam carving. Here seam carving refers to delete through horizontal or vertical line of pixels across the whole image to achieve image scaling effect. In order to maintain the characteristics of the image pixels to delete the importance of the image lines must be weakest. The importance of the pixel lines is determined in accordance with the type of scene images of different energy content. That is, the place with the more energy and the richer texture of the image should be retained. So the horizontal and vertical lines having the lowest energy are the object of inspection. By constantly deleting the low-energy line it can repair the image as the original scene.




For an original image G of m*n, where m and n are the row and column of the image respectively. Fish obtained the corresponding energy matrix A. He knew every time a seam with the lowest energy should be carved. That is, the line with the lowest sum of energy passing through the pixels along the line, which is a 8-connected path vertically or horizontally.

Here your task is to carve a pixel from the first row to the final row along the seam. We call such seam a vertical seam.

Input

There several test cases. The first line of the input is an integer T, which is the number of test cases, 0

[code]#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=110;
const int INF=0x3f3f3f3f;
int N,M;
int dp[maxn][maxn];
int a[maxn][maxn];
int path[maxn][maxn];

int main()
{
    int T,cas=1;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&N,&M);
        for(int i=1;i<=N;i++)
            for(int j=1;j<=M;j++)scanf("%d",&a[i][j]);
        memset(dp,INF,sizeof(dp));
        memset(path,-1,sizeof(path));
        for(int i=1;i<=M;i++)dp
[i]=a
[i];
        for(int i=N-1;i>=1;i--)
        {
            for(int j=1;j<=M;j++)
            {
                dp[i][j]=dp[i+1][j]+a[i][j];
                path[i][j]=j;
                if(j-1>0&&dp[i+1][j-1]+a[i][j]<dp[i][j])
                {
                    dp[i][j]=dp[i+1][j-1]+a[i][j];
                    path[i][j]=j-1;
                }
                if(j+1<=M&&dp[i+1][j+1]+a[i][j]<=dp[i][j])
                {
                    dp[i][j]=dp[i+1][j+1]+a[i][j];
                    path[i][j]=j+1;
                }
            }
        }
        int ans,maxv=INF;
        for(int i=1;i<=M;i++)
            if(dp[1][i]<=maxv)maxv=dp[1][i],ans=i;
        bool first=true;
        printf("Case %d\n",cas++);
        for(int i=1;i<=N;i++)
        {
            printf("%d",ans);
            if(i!=N)printf(" ");
            else printf("\n");
            ans=path[i][ans];
        }
    }
    return 0;
}


Maze

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 100000/100000 K (Java/Others)

Total Submission(s): 763 Accepted Submission(s): 273

Problem Description

This story happened on the background of Star Trek.

Spock, the deputy captain of Starship Enterprise, fell into Klingon’s trick and was held as prisoner on their mother planet Qo’noS.

The captain of Enterprise, James T. Kirk, had to fly to Qo’noS to rescue his deputy. Fortunately, he stole a map of the maze where Spock was put in exactly.

The maze is a rectangle, which has n rows vertically and m columns horizontally, in another words, that it is divided into n*m locations. An ordered pair (Row No., Column No.) represents a location in the maze. Kirk moves from current location to next costs 1 second. And he is able to move to next location if and only if:

Next location is adjacent to current Kirk’s location on up or down or left or right(4 directions)

Open door is passable, but locked door is not.

Kirk cannot pass a wall

There are p types of doors which are locked by default. A key is only capable of opening the same type of doors. Kirk has to get the key before opening corresponding doors, which wastes little time.

Initial location of Kirk was (1, 1) while Spock was on location of (n, m). Your task is to help Kirk find Spock as soon as possible.

Input

The input contains many test cases.

Each test case consists of several lines. Three integers are in the first line, which represent n, m and p respectively (1<= n, m <=50, 0<= p <=10).

Only one integer k is listed in the second line, means the sum number of gates and walls, (0<= k <=500).

There are 5 integers in the following k lines, represents xi1, yi1, xi2, yi2, gi; when gi >=1, represents there is a gate of type gi between location (xi1, yi1) and (xi2, yi2); when gi = 0, represents there is a wall between location (xi1, yi1) and (xi2, yi2), ( | xi1 - xi2 | + | yi1 - yi2 |=1, 0<= gi <=p )

Following line is an integer S, represent the total number of keys in maze. (0<= S <=50).

There are three integers in the following S lines, represents xi1, yi1 and qi respectively. That means the key type of qi locates on location (xi1, yi1), (1<= qi<=p).

Output

Output the possible minimal second that Kirk could reach Spock.

If there is no possible plan, output -1.

Sample Input

4 4 9

9

1 2 1 3 2

1 2 2 2 0

2 1 2 2 0

2 1 3 1 0

2 3 3 3 0

2 4 3 4 1

3 2 3 3 0

3 3 4 3 0

4 3 4 4 0

2

2 1 2

4 2 1

Sample Output

14

题意:有一个迷宫,格子之间有门或墙,有p种门,S个钥匙,问从(1,1)走到(n,m)最短时间

思路:还是普通的bfs,只不过是加一个状态,保存当前有哪些钥匙

[code]#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=55;
int N,M,P,K,S;
struct node
{
    int x,y,t;
    int S;
    node()=default;
    node(int a,int b,int c,int d):x(a),y(b),t(c),S(d){}
};
int gate[maxn][maxn][maxn][maxn];
int key[maxn][maxn];
bool vis[maxn][maxn][1<<11];
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
int BFS(int sx,int sy)
{
    memset(vis,0,sizeof(vis));
    queue<node> q;
    node B;
    if(key[sx][sy])
        q.push(node(sx,sy,0,key[sx][sy]));
    else q.push(node(sx,sy,0,0));
    while(!q.empty())
    {
        node A=q.front();q.pop();
        for(int i=0;i<4;i++)
        {
            int tx=A.x+dx[i];
            int ty=A.y+dy[i];
            if(tx<1||tx>N||ty<1||ty>M)continue;
            int g=gate[A.x][A.y][tx][ty];
            if(g==0)continue;
            if(g>0)
            {
                if(!(A.S&(1<<(g-1))))
                    continue;
            }
            int tmpS=A.S;
            if(key[tx][ty])tmpS|=key[tx][ty];
            if(vis[tx][ty][tmpS])continue;
            vis[tx][ty][tmpS]=1;
            if(tx==N&&ty==M)return A.t+1;
            q.push(node(tx,ty,A.t+1,tmpS));
        }
    }
    return -1;
}
int main()
{
    while(scanf("%d%d%d",&N,&M,&P)!=EOF)
    {
        scanf("%d",&K);
        memset(gate,-1,sizeof(gate));
        memset(key,0,sizeof(key));
        for(int i=1;i<=K;i++)
        {
            int a,b,c,d,e;
            scanf("%d%d%d%d%d",&a,&b,&c,&d,&e);
            gate[a][b][c][d]=gate[c][d][a][b]=e;
        }
        scanf("%d",&S);
        for(int i=1;i<=S;i++)
        {
            int x,y,t;
            scanf("%d%d%d",&x,&y,&t);
            key[x][y]|=(1<<(t-1));
        }
        printf("%d\n",BFS(1,1));
    }
    return 0;
}


Smart Software Installer

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 471 Accepted Submission(s): 143

Problem Description

The software installation is becoming more and more complex. An automatic tool is often useful to manage this process. An IT company is developing a system management utility to install a set of software packages automatically with the dependencies. They found that reboot is often required to take effect after installing some software. A software package cannot be installed until all software packages it depends on are installed and take effect.

In the beginning, they implemented a simple installation algorithm, but the system would reboot many times during the installation process. This will have a great impact on the user experience. After some study, they think that this process can be further optimized by means of installing as much packages as possible before each reboot.

Now, could you please design and implement this algorithm for them to minimize the number of restart during the entire installation process?

Input

The first line is an integer n (1 <= n <= 100), which is the number of test cases. The second line is blank. The input of two test cases is separated by a blank line.

Each test case contains m (1 <= n <= 1000) continuous lines and each line is no longer than 1024 characters. Each line starts with a package name and a comma (:). If an asterisk (*) exists between the package name and the comma, the reboot operation is required for this package. The remaining line is the other package names it depends on, separated by whitespace. Empty means that there is no dependency for this software. For example, “a: b” means package b is required to be installed before package a. Package names consist of letters, digits and underscores, excluding other special symbols.

Assume all packages here need to be installed and all referenced packages will be listed in an individual line to define the reboot property. It should be noted that cyclic dependencies are not allowed in this problem.

Output

For each test case, you should output a line starting with “Case #: ” (# is the No. of the test case, starting from 1) and containing the reboot count for this test case. (Refer to the sample format)

Sample Input

2

glibc:

gcc*: glibc

uefi*:

gcc*:

raid_util*: uefi

gpu_driver*: uefi

opencl_sdk: gpu_drivergcc

Sample Output

Case 1: 1

Case 2: 2

题意:告诉你软件之间的依赖关系,带*的是需要重启才生效的,问最小重启几次。

思路:转自:hdu5098

很神奇,相当于先把不需要重启的全部按完,然后把暴露在最外面的需要重启的一块按完,重启一次

[code]#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<sstream>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=10240;
int in[maxn],out[maxn],reboot[maxn];
int tot,cnt;
int head[maxn];
map<string,int> mp;
struct node
{
    int v,next;
}edge[maxn];
void init()
{
    tot=cnt=0;
    mp.clear();
    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
    memset(reboot,0,sizeof(reboot));
    memset(head,-1,sizeof(head));
}
char soft[maxn*10];
void add_edge(int x,int y)
{
    edge[tot].v=y;
    edge[tot].next=head[x];
    head[x]=tot++;
}
int topo()
{
    queue<int> q1,q2;
    for(int i=1;i<=cnt;i++)
    {
        if(in[i]==0)
        {
            if(reboot[i])q2.push(i);
            else q1.push(i);
        }
    }
    int ans=0;
    while(!q1.empty()||!q2.empty())
    {
        if(q1.empty()&&!q2.empty())
        {
            ans++;
            while(!q2.empty())
            {
                q1.push(q2.front());
                q2.pop();
            }
        }
        while(!q1.empty())
        {
            int u=q1.front();q1.pop();
            for(int i=head[u];i!=-1;i=edge[i].next)
            {
                int v=edge[i].v;
                in[v]--;
                if(in[v]==0)
                {
                    if(reboot[v])q2.push(v);
                    else q1.push(v);
                }
            }
        }
    }
    return ans;
}
int main()
{
    int T,cas=1;
    scanf("%d",&T);
    getchar();getchar();
    string s;
    while(T--)
    {
        init();
        while(getline(cin,s))
        {
            if(s[0]=='\0')break;
            istringstream ss(s);
            ss>>soft;
            int len=strlen(soft);
            int flag=0;
            if(soft[len-2]=='*')
            {
                flag=1;
                soft[len-2]='\0';
            }
            else soft[len-1]='\0';
            string id(soft),name;
            if(mp.find(id)==mp.end())
            {
                mp[id]=++cnt;
            }
            reboot[mp[id]]=flag;
            while(ss>>name)
            {
                if(mp.find(name)==mp.end())
                {
                    mp[name]=++cnt;
                }
                add_edge(mp[name],mp[id]);
                out[mp[name]]++;
                in[mp[id]]++;
            }
        }
        printf("Case %d: %d\n",cas++,topo());
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: