链接:https://cn.vjudge.net/contest/316356
来源:vjudge
文章目录
ZOJ 2109 FatMouse’ Trade(背包问题)
题解:https://blog.csdn.net/qq_42217376/article/details/98852231
HDU 6180 Schedule(任务调度)
题解:https://blog.csdn.net/qq_42217376/article/details/98860156
ZOJ 1076 Gene Assembly(区间调度)
题解:https://blog.csdn.net/qq_42217376/article/details/98865383
POJ 1230 Pass-Muraille
题目地址:http://poj.org/problem?id=1230
题意:魔术师可以表演穿墙术,题目给出了墙的俯视图,我们规定对于每一列魔术师最多只能穿过k面墙,若最终俯视图满足这个条件,那么我们最少需要拆除多少面墙?注意此题输入的坐标不一定是按照从小到大输入的。
思路:我们先找到墙最大能够到达哪一列,然后遍历这些列,对区间进行遍历,找到当前列有几面墙 sum,若 sum ≤ k,那么不用删除任何一面墙,否则,就需要拆除 sum - k 面墙,并且拆除的墙都是右方最长的墙。我们一面一面的删除,对于每次拆除我们都遍历当前的所有区间找到最长的那面墙拆除(使其右端点变为 -1)。重复这样这样的过程直到每一列都满足条件即可。
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
const int Max_n=110;
int a[Max_n];
struct Edge{
int l,r;
}edge[Max_n];
int main(){
int T;
scanf("%d",&T);
while(T--){
int n,k;
scanf("%d%d",&n,&k);
int maxr=-1;
for(int i=1;i<=n;i++){
int y;
scanf("%d%d%d%d",&edge[i].l,&y,&edge[i].r,&y);
if(edge[i].l>edge[i].r) swap(edge[i].l,edge[i].r);
maxr=max(maxr,edge[i].r);
}
///cout<<maxr<<endl;
int ans=0;
for(int i=0;i<=maxr;i++){///遍历列
int sum=0;///当前列可以穿过的墙数
for(int j=1;j<=n;j++){
if(i>=edge[j].l&&i<=edge[j].r)
sum++;//找到当前列能够穿过的墙数
}
sum-=k;
while(sum>0){
sum--;ans++;
int tmaxr=-1,inx=-1;
for(int j=1;j<=n;j++){///找到当前列可以穿过墙的最右边最远的墙
if(i>=edge[j].l&&i<=edge[j].r&&tmaxr<edge[j].r){
tmaxr=edge[j].r;
inx=j;///记录最右边的墙的下标
}
}
edge[inx].r=-1;
}
}
printf("%d\n",ans);
}
return 0;
}
POJ 2287 Tian Ji – The Horse Racing(田忌赛马)
题目地址:http://poj.org/problem?id=2287
题意:田忌和齐王各有三种马,问在比赛结束后田忌最多可以赚到多少钱?注意田忌赚到的钱可以为负数。
思路:
1、田忌最快的马 > 齐王最快的马 直接比赢一次(不管和齐王的哪一比较都能赢,此时和最快的比贡献最大)
2、田忌最快的马 < 齐王最快的马 田忌最慢的马和齐王最快的马比输一次(此时损耗最快的贡献最大)
3、田忌最快的马 = 齐王最快的马
<1> 田忌最慢的马 > 齐王最慢的马 直接比赢一次(齐王最慢的马一定要输一场,输给最慢的马贡献最大)
<2>其他 田忌最慢的马和齐王最快的马比 (田忌最慢的马一定要输一次,输给最快的马贡献最大)此时如果最慢的马 < 最快的马的时候才算输
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
const int Max_n=1e3+10;
int a[Max_n],b[Max_n];
bool cmp(int a,int b){
return a>b;
}
int main(){
int n;
while(scanf("%d",&n)&&n){
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
for(int i=0;i<n;i++)
scanf("%d",&b[i]);
sort(a,a+n,cmp);
sort(b,b+n);
int l=0,r=n-1,ans=0,mmin=0;
while(l<n&&r>=mmin){
if(a[l]>b[r]){//田忌最快>齐王最快
ans++;//赢
l++;r--;//直接比
}else if(a[l]<b[r]){//田忌最快<齐王最快
ans--;//输
n--;r--;//田忌最慢 齐王最快
}else{//田忌最快=齐王最快
if(a[n-1]>b[mmin]){//田忌最慢>齐王最慢
ans++;//赢
n--;mmin++;//直接比
}else{//田忌最慢<=齐王最慢
if(a[n-1]<b[r])//田忌最慢<齐王最快
ans--;//输
n--;r--;//田忌最慢 齐王最快
}
}
}
printf("%d\n",ans*200);
}
return 0;
}
POJ 1065 Wooden Sticks(任务调度)
题目地址:http://poj.org/problem?id=1065
题意:n根木棍组成一堆,每根棍子的长度和重量事先知道。这些木棍要被木工机器一个接一个地处理,机器准备处理一根棍子需要时间,被称为启动时间。启动时间与清洁操作和改变机器中的工具和外形有关。木工机器的启动时间给出如下:
n根木棍组成一堆,每根棍子的长度和重量事先知道。这些木棍要被木工机器一个接一个地处理,机器准备处理一根棍子需要时间,被称为启动时间。启动时间与清洁操作和改变机器中的工具和外形有关。木工机器的启动时间给出如下:
- (a) 第一根木棍的启动时间是1分钟;
- (b) 在处理好长度为l,重量为w的一根木棍后,如果下一根长度为l’且重量为w’木棍满足l≤ l’ 并且w≤w’,则机器对下一根木棍不需要启动时间;否则,机器需要1分钟来启动。
- 给出n根木棍组成的一堆,请求出处理这一堆木棍的最小启动时间。例如,如果有5根木棍,,长度和距离组成的对是( 9 , 4 ) , ( 2 , 5 ) , ( 1 , 2 ) , ( 5 , 3 ) 和 ( 4 , 1 ),那么最小的启动时间是2分钟,处理的对的序列是 ( 4 , 1 ) , ( 5 , 3 ) , ( 9 , 4 ) , ( 1 , 2 ) , ( 2 , 5 )。
问最小的启动时间,即最少用多少机器可以处理完这些木棍。
思路:我们先按照木根的 l 为关键字从大到小排序,然后遍历这些木棍,对于 l 很显然我们无需判断它是否与之前的木棍冲突,只需要判断 w 是否能够用当前已经启动的机器去处理,如果 *s.begin() ≤ 当前任务的 w 就代表已经启动的机器中有可以可以处理这根木棍的,为了找到最少的机器,我们找到最接近当前木棍最近的木棍的重量(如果每次都找最小的w去贪心的话,有可能存在后面的棍子中有更小w适合当前小的w,但是更新过以后就不能适合这个机器(参考样例1)),这样就转换成了任务调度的问题。
#include<cstdio>
#include<queue>
#include<set>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int Max_n=5e3+10;
struct Node{
int l,w;
bool operator <(const Node &a) const {
return w<a.w;
}
}node[Max_n];
bool cmp(Node a,Node b){
if(a.l==b.l)
return a.w<b.w;
return a.l<b.l;
}
multiset<int>s;//维护每台机器的正在处理的棍子重量w
int main(){
int T;
scanf("%d",&T);
while(T--){
s.clear();
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&node[i].l,&node[i].w);
sort(node+1,node+n+1,cmp);//按照长度排序
int sum=0;
for(int i=1;i<=n;i++){//遍历每一根根子(对于l都不冲突,判断w是否冲突即可)
if(s.empty()){
sum++;
s.insert(node[i].w);
continue;
}
if(*s.begin()<=node[i].w){//如果这个根子可以被一台机器做
s.erase(--s.upper_bound(node[i].w));//找到距离这个根子最近的w(当前正在加工的)
s.insert(node[i].w);//更新w
}else{//冲突
sum++;
s.insert(node[i].w);//更新w
}
}
printf("%d\n",sum);
}
return 0;
}
POJ 1328 Radar Installation
题目地址:http://poj.org/problem?id=1065
题意:给你一些岛屿的坐标(一定在海岸线的上方),你可以在海岸线上放置一些雷达(雷达可扫描的半径已经给出)(保证可以扫描到所有的岛屿),问最少需要放置多少雷达?
思路:对于每一个岛屿,先预处理出雷达可以放置的位置。对于这些雷达可以放置的位置,按照右端点从小到大排序。遍历所有的区间(一个区间代表一个岛屿雷达可以放置的位置),用一个变量记录现在雷达的位置,如果某一个区间的左端点在雷达的左边说明雷达可以扫描到这个岛屿,否则(node[i].l>inx),就需要增加一个雷达,并且改变当前雷达的位置。直到所有的区间都处理完毕即可。
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
const int Max_n=1e3+10;
int n,d;
struct Node{
double l,r;
bool operator<(const Node &a)const{
if(r==a.r)
return l<a.l;
return r<a.r;
}
}node[Max_n];
int main(){
int T=0;
while(scanf("%d%d",&n,&d)&&n+d){
for(int i=1;i<=n;i++){//先处理出每一个岛可以放置雷达的范围
double x,y,add;
scanf("%lf%lf",&x,&y);
if(y>d||d<0) d=-1;
add=sqrt(d*d-y*y);
node[i].l=x-add;node[i].r=x+add;
}
if(d==-1){
printf("Case %d: -1\n",++T);
}else{//所有岛屿都可以扫描到
sort(node+1,node+n+1);//按照右端点排序
int sum=1;
double inx=node[1].r;///这里写成了int....(当前雷达的位置)
for(int i=2;i<=n;i++){
if(node[i].l>inx){//当前岛的左端点没有与雷达的位置重合
sum++;//当前雷达一定扫描不到
inx=node[i].r;//更新雷达的位置
}
}
printf("Case %d: %d\n",++T,sum);
}
}
return 0;
}
POJ 1505 Copying Books(二分 + 最小化最大值)
题解:https://blog.csdn.net/qq_42217376/article/details/98873195