码迷,mamicode.com
首页 > 其他好文 > 详细

[BestCoder] Round #2

时间:2015-02-01 16:12:31      阅读:283      评论:0      收藏:0      [点我收藏+]

标签:

1001

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4883

题意为:有n组客人来吃饭,给出每组客人的人数及用餐开始时间,结束时间,格式为hh:mm;要求一组客人来的时候就必须给其安排位子
,问最少需要多少把椅子才能做到(一位客人需要一把椅子).

方法:time[i],表示第i分钟有多少用餐的人,也就是需要多少把椅子,将开始时间,结束时间转化为分钟为单位的时间。
注意边界一组的结束和另一组的开始如果相同,则不需要额外的椅子,因此把每组的结束时间都-1. 对于每一组人,开始时间到结束时间
循环time[i]+=该组的人数。  最后再遍历time[i]数组,从中找到最大值即为该题的答案。

代码:

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <stdlib.h>
#include <cmath>
#include <iomanip>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cctype>
using namespace std;
#define ll long long
int n;
int time[1442];

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(time,0,sizeof(time));
        scanf("%d",&n);
        int sh,sm;
        int eh,em;
        int cnt=0;
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&cnt);
            scanf("%d:%d",&sh,&sm);
            scanf("%d:%d",&eh,&em);
            int s=sh*60+sm;
            int e=eh*60+em;
            e--;
            for(int i=s;i<=e;i++)
            {
                time[i]+=cnt;
            }
        }
        for(int i=0;i<1440;i++)
        {
            if(ans<time[i])
                ans=time[i];
        }
        printf("%d\n",ans);
    }
    return 0;
}
1002

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4884

题意为:一共有n种炒饭,每种炒饭炒一次都花t分钟,炒一次是k份的量,每次只能炒同一种炒饭,有m个客人,给出每个客人的到来时间,以及所要炒饭的种类和数量,问每个客人的最早离开时间.
一开始第三组测试数据没看懂
n=2 t=5 k=4 m=2
08:00 1 1
08:04 1 1
第一位客人8点的时候要了第一种炒饭1分,第二位客人8点04的时候要了第1种炒饭1份,那直接炒4份不就可以了吗...两位客人都是0点5分离开,坑啊,不能这样,正确的应该是这样联系实际,首先来的是第一位客人要了第一种炒饭1份,那么就得花5分钟就只炒1份,虽然这5分钟内有第二位客人来了,但是不能给他炒,等第一位客人走了以后,再给第二位客人来炒。
还有另外种情况,后面的可以加在前面炒
还是前面的数据,只不过客人的信息该为了
08:00 1 6
08:02 2 1
08:03 1 X
首先第一位客人,要了6份,因为一次最多炒4份,所以第一份炒完4份后,时间为8点05,这时候第二位和第三位都来了,正好第三位和第一位要的是一样的,那么下一次再为第一位客人炒饭(因为还差2份)时,就可以顺便为第三位客人也炒出来,如果X=2的话,那么最后一次为第一位客人炒饭,2份给它,2份给第三位个人就可以了,两位客人同时离开,如果X<2的话,假设为1,那么最后一次只要炒3份就可以了。如果X>2的话,那么炒出来2分给第三位客人留着,到了他的时候,再给他炒X-2份就够了.
写这道题,头晕晕的......

代码:

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <stdlib.h>
#include <cmath>
#include <iomanip>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cctype>
using namespace std;
#define ll long long
const int maxn=1002;//最大种类数
int n,t,K,M;//n为种类数,t为一次炒饭的时间,k为一次可以炒多少份,m是有m个客人
bool done[maxn];

struct Customer
{
    int h,m;
    int time;
    int kind;
    int num;
    int ans;
}cus[maxn];

void output(int t)
{
    int h=t/60;
    h%=24;
    int m=t%60;
    if(h<=9)
        printf("0%d:",h);
    else
        printf("%d:",h);
    if(m<=9)
        printf("0%d\n",m);
    else
        printf("%d\n",m);
}
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d%d",&n,&t,&K,&M);
        memset(done,0,sizeof(done));
        for(int i=1;i<=M;i++)
        {
            scanf("%d:%d %d %d",&cus[i].h,&cus[i].m,&cus[i].kind,&cus[i].num);
            cus[i].time=cus[i].h*60+cus[i].m;
        }
        int curtime=-1;//当前时间
        for(int i=1;i<=M;i++)
        {
            if(done[i])
                continue;
            if(cus[i].time>=curtime)
                curtime=cus[i].time;

            int c=(cus[i].num)/K;//为第i个顾客需要炒几次饭
            if(cus[i].num%K!=0)
                c++;
            //cout<<"tt"<<tt<<endl;
            cus[i].ans=curtime+c*t;//第i个顾客离开时间
            //int curt=curtime+cus[k].num/K*t;
            int curt=cus[i].ans-t;//为第i个顾客最后一次炒饭开始的时间,
            //因为这时候要看看后面的顾客有没有和当前顾客要的一样的,顺带着“炒出来一部分”

            curtime=cus[i].ans;
            int left=c*K-cus[i].num;//最后一次可以多炒一部分,比如每次炒4份,当前顾客要10份,那么得炒3次,第三次炒可以炒4份,那么就会多出来2份

            done[i]=1;
           // cout<<"kk"<<k<<"left"<<left<<endl;
            for(int j=i+1;j<=M;j++)
            {
                if(cus[j].time>curt)
                    break;
                if(cus[j].kind!=cus[i].kind)
                    continue;
                if(left>=cus[j].num)//当前顾客多出的饭可以直接给后面需要的
                {
                   // cout<<"inininininin"<<endl;
                    cus[j].ans=cus[i].ans;
                    done[j]=1;
                    left-=cus[j].num;
                }
                else
                {
                    cus[j].num-=left;
                    left=0;
                    break;
                }

            }
            //kindn[cus[k].kind]+=left;
            //cout<<cus[k].kind<<"  sssssssss   "<<left<<endl;
        }
        for(int i=1;i<=M;i++)
            output(cus[i].ans);
        if(T)
        printf("\n");
    }
    return 0;
}

1003

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4885

解题思路:
题意为在一个二维坐标中,给出起点,终点,以及n个加油站的坐标,车子从起点出发,且是加满油的,车子始终保持直线行驶,且只能在起点,加油站或终点之间行驶,每次经过一个加油站都必须加满油,且加满油只有最多可以走L长度,问要从起点走到终点,如果可以的话,最少经过多少加油站,如果不可以,输出impossible
一开始的思路是,一共n=n+2个节点(包含起点和终点),那么则有 n*(n-1)/2条边,再这里边挑出可行边,即边的长度<=给定的L,然后另可行边的权值为1,建立邻接矩阵,跑一遍最短路就可以了,最后答案为dis[n]-1。
但这种思路细节没有考虑到,比如起点坐标 0,0   第一个加油站坐标  3,0  第二个  4,0  第三个 5,0 ,L=6,可以发现这四个点在同一条直线上,而且从起点到第三个加油站相连的边长度也小于L,是可行边,按照上边的思路则该边的权值为1,但是第二个第三个加油站都在该边上,要想从起点到达第三个加油站,就必须经过第一个和第二个加油站,那么权值应该是3,而不是前面所说的1.
所以前面犯的错误就是加边加多了,如果和第i个节点组成的边中有斜率一样的,则这些边共线,那么只能连接最短的边,其他共线的边均舍去。
方法为每条边均为一个结构体,其中保存终点和边的斜率及边长,对每个节点都有一个结构体类型的vector,保存以该节点为起点的所有边,当找到一个可行边时,去里面找看看有没有与其斜率相同的,如果有,再比较两条边的长度,保存长度小的边,去掉另外一条边,当没有斜率相同的话,直接加边就可以了。加边也就是使邻接矩阵mp[i][j]=1,去边也就是令mp[i][j]=inf。这样建好图,跑一下最短路就可以了,答案为dis[n]-1.

代码:

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <stdlib.h>
#include <cmath>
#include <iomanip>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cctype>
using namespace std;
#define ll long long
const int maxn=1010;
const int inf=0x3f3f3f3f;
int dis[maxn];
bool vis[maxn];
int n;
int L;
int mp[maxn][maxn];

struct Node
{
    int x,y;
}node[maxn];

struct Edge//边的结构体,指向谁,长度是多少
{
    int to;
    int up;
    int down;//斜率的分子,分母
    double len;
};
vector<Edge>vc[maxn];//每个点都有一个vector,用来存与该点相连的可行边


double distan(Node a,Node b)
{
    return sqrt(double((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)));
}

void dijkstra(int start)
{
    //**第一步:初始化,dis[]为最大,vis均为0(都未加入集合)
    memset(dis,inf,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[start]=0;    //注意不能写vis[start]=1,因为这时候第一个节点还没有被访问,下面循环中,第一个选择的就是第一个节点,切记</span>
    //**第二步:找dis[]值最小的点,加入集合,并更新与其相连的点的dis[]值

    //一开始集合里没有任何点,下面的循环中,第一个找到的点肯定是源点

    for(int i=1;i<=n;i++)
    {
        //寻找dis[]最小的点,加入集合中
        int MinNumber,Min=inf;//MinNumber为dis[]值最小的点的编号
        for(int j=1;j<=n;j++)
        {
            if(dis[j]<Min&&!vis[j])
            {
                Min=dis[j];
                MinNumber=j;
            }
        }
        //找到dis[]最小的点,加入集合,更新与其相连的点的dis值
        vis[MinNumber]=1;
        for(int j=1;j<=n;j++)
            if(dis[MinNumber]+mp[MinNumber][j]<dis[j])
            dis[j]=dis[MinNumber]+mp[MinNumber][j];
    }
}


int main()
{
    int t;scanf("%d",&t);
    while(t--)
    {

        for(int i=0;i<maxn;i++)
            vc[i].clear();
        scanf("%d%d",&n,&L);
        n+=2;
        scanf("%d%d",&node[1].x,&node[1].y);
        scanf("%d%d",&node[n].x,&node[n].y);
        for(int i=2;i<=n-1;i++)
            scanf("%d%d",&node[i].x,&node[i].y);
        memset(mp,inf,sizeof(mp));

        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)
        {
            double l=distan(node[i],node[j]);//之间的距离
            if((L-l)>=0)//首先看是否满足初步条件,,可行边
            {
                int up=node[j].y-node[i].y;
                int down=node[j].x-node[i].x;//该点的斜率
                bool ok=0;//看能不能找到斜率相同的边
                for(int k=0;k<vc[i].size();k++)
                {
                   // if((up*vc[i][k].down==down*vc[i][k].up&&up!=0&&down!=0&&up!=0&&vc[i][k].down!=0&&vc[i][k].up!=0)||(up==0&&vc[i][k].up==0))
                        if(up*vc[i][k].down==down*vc[i][k].up)
                    {//两种情况,斜率不存在,up全部为0,斜率存在
                       // cout<<"i "<<i<<"j "<<j<<endl;
                        ok=1;//找到了斜率相同的可行边
                        if(l<vc[i][k].len)//斜率相同的两条边,目前边的长度比已有边的长度小,则去掉已有边,加入目前边
                        {
                            mp[i][vc[i][k].to]=inf;
                            mp[vc[i][k].to][i]=inf;
                            mp[i][j]=1;
                            mp[j][i]=1;
                            Edge edge;
                            edge.to=j;
                            edge.up=up;
                            edge.down=down;
                            edge.len=l;
                            vc[i].push_back(edge);
                        }
                        break;
                    }
                }
                if(!ok)//找不到斜率相同的,则加入新边
                {
                            Edge edge;
                            edge.to=j;
                            edge.up=up;
                            edge.down=down;
                            edge.len=l;
                            mp[i][j]=1;
                            mp[j][i]=1;
                            vc[i].push_back(edge);
                }
            }
        }
        dijkstra(1);
        if(dis[n]==inf)
            printf("impossible\n");
        else
            printf("%d\n",dis[n]-1);

    }
    return 0;
}


[BestCoder] Round #2

标签:

原文地址:http://blog.csdn.net/sr_19930829/article/details/43371779

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!