/*
POJ 3262
有n头牛在糟蹋庄稼。把第i头牛牵回家需要ti分钟。第i头牛每分钟会摧毁di的庄稼。每次只能牵一头牛走。问怎么牵使损失最少。
思路:考虑a,b两牛。先牵a牛和b牛的损失分别为。2*d[b]*t[a],2*d[a]*t[b]。设先牵a更优。2*d[b]*t[a]<2*d[a]*t[b].
所以根据优先级排序然后依次牵就是最优的选择。
1 在二个中间选择之中,能根据time/eat小的那个为最优解
证明:二个羊中 A,B,属性分别为分别为eatA,timeA,eatB,timeB
选A的时候损失timeA*eatB
选B的时候损失timeB*eatA
双方同除以eatA*eatB.
令time/eat为一个羊的比率x
可以证明x小的那个为最优解.
*/
#include<cstdio>
#include<algorithm>
#define MAXN 111111
#define MAXM 222222
const int INF=0x3f3f3f3f;
using namespace std;
struct node{
int x,y;
}a[MAXN];
int n;
bool cmp(node x,node y){//乘积排序即可
return x.x*y.y<x.y*y.x;
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d%d",&a[i].x,&a[i].y);
a[i].x*=2;//一来一回需要时间两倍
}
sort(a,a+n,cmp);
long long ans=0;
long long sum=0;
for(int i=0;i<n;i++){
ans+=sum*(long long )a[i].y;
sum+=a[i].x;//一直吃花的时间
}
printf("%lld\n",ans);
}
/*
HDU 3466
这是一道01背包的变形题,题目增加了一个限制条件,即当你所拥有的钱数大于某个限定值时才可以购买该物品。
按照q - p以由大到小的顺序排序,然后进行01背包的DP即可。
题意是: 给你一些钱 m ,然后在这个国家买东西, 共有 n 件物品,每件物品有 价格 P 价值 V 还有一个很特别的属性 Q, Q 指 你如过想买这件物品 你的手中至少有这钱Q 。 虽然你只要花费 钱P ,但你的手中至少有钱Q,如果不足Q ,不能买。问给你钱M ,列出N件物品,最多能获得多少价值的东西。。。。
按 Q-P 的大小 ,从小到大排序,然后按照0-1 背包的思想
dp[c]=max(dp[c],dp[c-p[i]])+v[i]; 最终 dp[m]就是结果。
为什么这样呢?A:p1,q1 B: p2,q2,先选A,则至少需要p1+q2的容量,而先选B则至少需要p2+q1,如果p1+q2>p2+q1,那么要选两个的话的就要先选A再选B,公式可换成q1-p1 < q2-p2,就按这样的方法排序最后的顺序就是最优的顺序。
*/
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN=5005;
int dp[MAXN];
struct Node{
int p,q,v;
}node[505];
bool cmp(Node a,Node b){
return (a.q-a.p)<(b.q-b.p);//按照之差递减排序
}
int main(){
int n,m;
while(~scanf("%d%d",&n,&m)){
for(int i=0;i<=m;i++)
dp[i]=0;
for(int i=0;i<n;i++){
scanf("%d%d%d",&node[i].p,&node[i].q,&node[i].v);
}
sort(node,node+n,cmp);
for(int i=0;i<n;i++){//0、1背包问题
for(int j=m;j>=node[i].p;j--){
if(j>=node[i].q)
dp[j]=max(dp[j],dp[j-node[i].p]+node[i].v);
}
}
int ans=0;//输出最大的值
for(int i=0;i<=m;i++)
if(ans<dp[i])
ans=dp[i];
printf("%d\n",ans);
}
}
/*
POJ 1862(贪心+优先队列)
题意很简单,就是给定你一系列的数值,任意挑选其中两个数a和b,得到一个新的数2*sqrt(a*b),然后再将这个新的个放回。一直这样下去,直到只剩下一个数。求剩下的这个数最小是多少。
使用贪心策略,不断挑选两个最大的数组成一个新的数并放回原数列,再挑选最大的两个数……最到只乘一个数为止。
*/
#include<cstdio>
#include<queue>
#include<cmath>
using namespace std;
int main(){
int n;
scanf("%d",&n);
double a,b,t;
priority_queue<double>p;
for(int i=0;i<n;i++){
scanf("%lf",&t);
p.push(t);
}
while(p.size()!=1){
a=p.top();
p.pop();
b=p.top();
p.pop();
t=2*sqrt(a*b);
p.push(t);
}
printf("%.3lf\n",p.top());
}
/*
POJ 3040
夫约翰要给奶牛Bessie发工资了(你们结婚吧,生个牛头人( ̄_ ̄|||) ),每周至少 C 元。约翰手头上有面值V_i的硬币B_i个,这些硬币的最小公约数为硬币的最小面值。求最多能发几周?
贪心策略是使多发的面额最小(最优解)。分三个阶段:
首先面额不小于C的硬币属于没办法节约的类型,先统统发掉。
然后对硬币面额从大到小尽量凑得接近C,允许等于或不足C,但是不能超出C。
接着按硬币面额从小到大凑满C(凑满的意思是允许超出一个最小面值,ps此处的最小面值指的是硬币剩余量不为0的那些硬币中的最小面值),凑满之后得出了最优解,发掉,进入步骤2.
这样就保证了每次都是当前的最优解,这个题很好地体现了贪心法的精髓。
*/
#include <cstdio>
#include<cstring>
#include <algorithm>
using namespace std;
const int INF =0x7fffffff;
typedef pair<int ,int > Coin;//货币 面值 数额
Coin coin[20];
int need[20];
int cmp(Coin x,Coin y){ //面值从大到小排序
return x.first>y.first;
}
int main(){
int N,C;
scanf("%d%d",&N,&C);
for(int i=0;i<N;i++)
scanf("%d%d",&coin[i].first,&coin[i].second);
int week=0;
for(int i=0;i<N;i++){
if(coin[i].first>=C){ // 面额不小于C的一定可以支付一周
week+=coin[i].second;
coin[i].second=0;
}
}
sort(coin, coin + N,cmp);
while(true){
int sum=C;// 等待凑足的sum
memset(need,0,sizeof(need));
for(int i=0;i<N;i++){ // 从大到小
if(sum>0&&coin[i].second>0){
int can_use=min(coin[i].second,sum/coin[i].first);
if(can_use>0){
sum-=can_use*coin[i].first;
need[i]=can_use;
}
}
}
// 没凑够的话。只能往回找最小的面值凑够 从小到大
for(int i=N-1;i>=0;i--){
if(sum>0&&coin[i].second>0){
int can_use=min(coin[i].second-need[i],(sum+coin[i].first)/coin[i].first);
if(can_use>0){
sum-=can_use*coin[i].first;
need[i]+=can_use;
}
}
}
if(sum>0)
break;
int add_up=INF; //使用该种发货币的方式最多可以持续的周数
for(int i=0;i<N;i++){
if(need[i]==0)
continue;
add_up=min(add_up,coin[i].second/need[i]);
}
week+=add_up;
for(int i=0;i<N;i++){
if(need[i]==0)
continue;
coin[i].second-=add_up*need[i];
}
}
printf("%d\n",week);
}
/*
题目:
POJ 2376
给定一个时间T和N个时间区间,求最少需要多少个区间覆盖总区间[1,T],无法覆盖区域[1,T]时输出-1。
例如T=10,有3个区间[1,7],[3,6],[8,10],则最少需要两个区间来覆盖,选择区间1和区间3。
解题思路:
使用贪心法。首先将区间按开始时间从小到大排序,开始时间相等按结束时间从小到大排序。
1 如果第一个区间不是从1开始,则无法覆盖,输出-1。
2 令当前覆盖到的时间time为开始时间为1的区间中结束时间的最大值。
3 从开始时间不为1的区间开始循环遍历。
4 选择合法区间中结束时间值最大的那个区间,合并到[1,time],合并后time为选择的区间的结束时间。所谓合法区间是指区间的起始时间start<=time+1,这样才能和区间[1,time]合并。如果没有找到合法区间或者找到的区间结束时间比time小,则无法覆盖,结束循环。
5 循环结束后,根据time是否大于等于T,输出结果。
*/
#include<cstdio>
#include<algorithm>
using namespace std;
typedef struct node{
int start,endx;
}interval;
interval data[25005];
int cmp(node a,node b){//按start从小到大,end从小到大排序
if(a.start==b.start)
return a.endx<b.endx;
return a.start<b.start;
}
int main(){
int t,n,time,i,j,ans,max_end;
scanf("%d %d",&n,&t);
for( i=0;i<n;i++)
scanf("%d %d",&data[i].start,&data[i].endx);
sort(data,data+n, cmp);
if(data[0].start!=1){//不是从1开始,无法覆盖
printf("-1\n");
return 0;
}
else{
time=data[0].endx;
i=1;//i指向下一个区间
while(data[i].start==1){
time=data[i].endx;i++;
}
}
ans=1;
while(time<t){
//使用贪心原则查找下一个区间,取合法区间中结束时间最大的那个
if(i>=n)
break;
j=i;
max_end=data[i].endx;
i++;
while(i<n&&data[i].start<=time+1){//起点的小于等于time+1 因为区间不能间隔
if(data[i].endx>max_end){
j=i;
max_end=data[i].endx;
}
i++;
}
if(max_end<=time || data[j].start>time+1)
break;
//结束时间没有增长或选择的区间为非法区间,无法覆盖
else{//增加一个区间,当前时间变为选择的区间的结束时间
ans++;
time=data[j].endx;
}
}
if(time<t)
printf("%d\n",-1);
else
printf("%d\n",ans);
}
/*
POJ 3190
题意:有N条线段,求最少要将这些线段分成几组,使得每组中的线段都没有重叠
按左端点排序,然后每次挑之前分的组中右端点最左的那组,如果有重叠,就新开一组。
可用优先级队列进行维护(右端点最左的)
*/
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=600000;
int n,use[maxn];
struct Node{
int l;//左端点
int r;//右端点
int pos;//位置
//重载优先队列的小于号 结束时间早为优先 右断点相等,左端点小的在前
bool operator <(const Node &a)const {
if(r==a.r)
return l>a.l;
return r>a.r;
}
}a[maxn];
priority_queue<Node> q;
//左端点按照从小到大排序
bool cmp(Node a,Node b){
if(a.l==b.l)
return a.r<b.r;
return a.l<b.l;
}
int main(){
while(~scanf("%d",&n)){
for(int i=0;i<n;i++){
scanf("%d%d",&a[i].l,&a[i].r);
a[i].pos=i;
}
sort(a,a+n,cmp);
q.push(a[0]);
int ans=1;
use[a[0].pos]=1;
for(int i=1;i<n;i++){
if(!q.empty()&&q.top().r<a[i].l){
use[a[i].pos]=use[q.top().pos];
q.pop();
}
else{
ans++;
use[a[i].pos]=ans;
}
q.push(a[i]);
}
printf("%d\n",ans);
for(int i=0;i<n;i++)
printf("%d\n",use[i]);
while(!q.empty()){
printf("%d %d\n",q.top().r,q.top().l);
q.pop();
}
}
}