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