贪心+huffman编码+模拟退火+分治(一)

(一)贪心

1.A - 今年暑假不AC

“今年暑假不AC?” 
“是的。” 
“那你干什么呢?” 
“看世界杯呀,笨蛋!” 
“@#$%^&*%...” 

确实如此,世界杯来了,球迷的节日也来了,估计很多ACMer也会抛开电脑,奔向电视了。 
作为球迷,一定想看尽量多的完整的比赛,当然,作为新时代的好青年,你一定还会看一些其它的节目,比如新闻联播(永远不要忘记关心国家大事)、非常6+7、超级女生,以及王小丫的《开心辞典》等等,假设你已经知道了所有你喜欢看的电视节目的转播时间表,你会合理安排吗?(目标是能看尽量多的完整节目) 

Input输入数据包含多个测试实例,每个测试实例的第一行只有一个整数n(n<=100),表示你喜欢看的节目的总数,然后是n行数据,每行包括两个数据Ti_s,Ti_e (1<=i<=n),分别表示第i个节目的开始和结束时间,为了简化问题,每个时间都用一个正整数表示。n=0表示输入结束,不做处理。 
Output对于每个测试实例,输出能完整看到的电视节目的个数,每个测试实例的输出占一行。Sample Input

12
1 3
3 4
0 7
3 8
15 19
15 20
10 15
8 18
6 12
5 10
4 14
2 9
0

Sample Output

5
解题思路:贪心思路:将每个数据用pair储存起来,根据结束时间进行从小到大排序,在循环模拟时,若果下一个的起始时间<上一个的结束时间,
则可以++,并将该结束时间作为下回判断的结束时间;否则循环下一个。
代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#define x first
#define y second
using namespace std;
const int N=110;
typedef  pair<int,int> PII;
int t;
PII f[N];
int main()
{
    int s,e,i,j,n;
    while(scanf("%d",&n)&&n)
    {
        for(i=0;i<n;i++)
        {
            scanf("%d%d",&s,&e);
            f[i].x=e,f[i].y=s;
        }
        sort(f,f+n);
        int ans=1;
        int tem=f[0].x;
        for(i=1;i<n;i++)
        {
            if(f[i].y>=tem)
            {
                ans++;
                tem=f[i].x;
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

2.B - 迷瘴

 

通过悬崖的yifenfei,又面临着幽谷的考验—— 
幽谷周围瘴气弥漫,静的可怕,隐约可见地上堆满了骷髅。由于此处长年不见天日,导致空气中布满了毒素,一旦吸入体内,便会全身溃烂而死。 
幸好yifenfei早有防备,提前备好了解药材料(各种浓度的万能药水)。现在只需按照配置成不同比例的浓度。 
现已知yifenfei随身携带有n种浓度的万能药水,体积V都相同,浓度则分别为Pi%。并且知道,针对当时幽谷的瘴气情况,只需选择部分或者全部的万能药水,然后配置出浓度不大于 W%的药水即可解毒。 
现在的问题是:如何配置此药,能得到最大体积的当前可用的解药呢? 
特别说明:由于幽谷内设备的限制,只允许把一种已有的药全部混入另一种之中(即:不能出现对一种药只取它的一部分这样的操作)。 
 

Input输入数据的第一行是一个整数C,表示测试数据的组数; 
每组测试数据包含2行,首先一行给出三个正整数n,V,W(1<=n,V,W<=100); 
接着一行是n个整数,表示n种药水的浓度Pi%(1<=Pi<=100)。 
Output对于每组测试数据,请输出一个整数和一个浮点数; 
其中整数表示解药的最大体积,浮点数表示解药的浓度(四舍五入保留2位小数); 
如果不能配出满足要求的的解药,则请输出0 0.00。 
Sample Input

3
1 100 10
100
2 100 24
20 30
3 100 24
20 20 30

Sample Output

0 0.00
100 0.20
300 0.23
解题思路:贪心思路就是优先选择浓度低的,对所有解药进行sort排序,再结合前缀和,从后往前进行遍历,找到第一个浓度小于等于目标浓度的体积时
结束,输出;特别注意:double x=((s[i]*1.0/100)*v)/((i+1)*v);
代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
using namespace std;
int c,n,v;
int f[110],s[110];
int w;
int main()
{
    int i,j;
    cin>>c;
    while(c--)
    {
        cin>>n>>v>>w;
        for(i=0;i<n;i++)
            cin>>f[i];
        double dow=w/100.00;
        sort(f,f+n);
        s[0]=f[0];
        for(i=1;i<n;i++)
        {
            s[i]=s[i-1]+f[i];
        }
        bool flag=false;
        for(i=n-1;i>=0;i--)
        {
            double x=((s[i]*1.0/100)*v)/((i+1)*v);
            if(x<dow||fabs(x-dow)<1e-8)
            {
                flag=true;
                cout<<(i+1)*v<<" ";
                printf("%.2f\n",x);
                break;
            }
        }
        if(flag==false)
            cout<<"0 0.00"<<endl;
    }
    return 0;
}

(二)模拟退火

1.Strange fuction

Now, here is a fuction: 
  F(x) = 6 * x^7+8*x^6+7*x^3+5*x^2-y*x (0 <= x <=100) 
Can you find the minimum value when x is between 0 and 100.

Input

The first line of the input contains an integer T(1<=T<=100) which means the number of test cases. Then T lines follow, each line has only one real numbers Y.(0 < Y <1e10)

Output

Just the minimum value (accurate up to 4 decimal places),when x is between 0 and 100.Sample Input

2
100
200

Sample Output

-74.4291
-178.8534
解题思路:该题可用二分的思想来解决。
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
double find(double x,double y)
{
    return 6*pow(x,7)+8*pow(x,6)+7*pow(x,3)+5*pow(x,2)-y*x;
}

double check(double y)
{
    double l=0,r=100;
    while(r-l>1e-8)
    {
        double mid=(l+r)/2;
        double rmid=(mid+r)/2;
        if(find(mid,y)<find(rmid,y))
            r=rmid;
        else
            l=mid;
    }
    return l;
}

int main()
{
    int t,i;
    double y;
    cin>>t;
    while(t--)
    {
        cin>>y;
        double key=check(y);
        printf("%.4f\n",find(key,y));
    }
    return 0;
}

 



posted @ 2020-02-03 12:55  清风紫雪  阅读(226)  评论(0编辑  收藏  举报