标签:
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;
}题目链接: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;
}
标签:
原文地址:http://blog.csdn.net/sr_19930829/article/details/43371779