zoukankan      html  css  js  c++  java
  • 套题 8.21

    . 1. 三角形
    (trokuti.cpp/c/pas)
     【 问题描述 】
     平面上有N条直线,用方程A i x + B i y +C i =0表示。这些直线没有三线共点的。

    现在要你计算出用这些直线可以构造出多少三角形?

    【输入格式】 】
     第1行:一个整数N(1 ≤ N≤ 300000)。
     下面N行:每行3个整数:Ai, Bi 和Ci,表示对应直线方程的系数。不超过10^9.

    输出格式】 】
    一行,一个整数。
    input 1
    6
    0 1 0
    -5 3 0
    -5 -2 25
    0 1 -3
    0 1 -2
    -4 -5 29
    input 2
    5
    -5 3 0
    -5 -3 -30
    0 1 0
    3 7 35
    1 -2 -1
    output 1
    10
    output 2

    10

    【 数据规模与约定】 】
     40%的数据,N ≤1000;
     对于100%的数据,N≤300000。

    太可恶了!!第四十行忘处理了,只得了10分。

    (也就是,最后一组斜率忘记加到数组中了)

     2 #include<queue>
     3 #include<cstdio>
     4 #include<algorithm>
     5 #include<cstring>
     6 #include<queue>
     7 #include<math.h>
     8 using namespace std;
     9 #define LL long long 
    10 LL n;
    11 double q[300009];
    12 int sum[300009],cnt;
    13 LL all;
    14 LL C(LL m,LL n)
    15 {
    16     if(n==2)    return (m-1)*m/2;
    17     if(n==3)    return m*(m-1)*(m-2)/6;
    18 }
    19 int main()
    20 {
    21     freopen("trokuti.in","r",stdin);
    22     freopen("trokuti.out","w",stdout);
    23     scanf("%lld",&n);
    24     
    25     double a,b,c;
    26     for(int i=1;i<=n;i++)
    27     {
    28         scanf("%lf%lf%lf",&a,&b,&c);            
    29          q[i]=a / b;        
    30     }
    31     
    32     sort(q+1,q+1+n);
    33     
    34     
    35     LL tot=1;
    36     for(int i=2;i<=n;i++)
    37     if(q[i]==q[i-1])
    38         ++tot;
    39     else sum[++cnt]=tot,tot=1;    
    40     sum[++cnt]=tot;
    41     all=C(n,3);
    42     for(int i=1;i<=cnt;i++)
    43     {
    44         if(sum[i]>=2)    all-=(n-sum[i])*C(sum[i],2);
    45         if(sum[i]>=3)    all-=C(sum[i],3);
    46     }
    47     cout<<all;
    48     return 0;
    49 }

     另一种做法。

    #include<iostream>
    #include<queue >
    #include<algorithm>
    #include<cstdio>
    using namespace std;
    double k[300009];
    int n,sum[300009],tot,cnt;
    int f[300009];double a,b,c;
    long long ans;
    int main()
    {
        freopen("trokuti.in","r",stdin);
        freopen("trokuti.out","w",stdout);
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf%lf",&a,&b,&c);
            k[i]=a/b;
        }
        sort(k+1,k+1+n);
        
        
        cnt=0;
        for(int i=1;i<=n+1;i++)
        {
            if(k[i]!=k[i-1])
                sum[cnt++]=tot,tot=1;
            else tot++;
        } 
        
        for(int i=1;i<=cnt;i++)    f[i]=f[i-1]+sum[i];
        for(int i=1;i<cnt;i++)
        ans+=(long long )(1LL*sum[i]*f[i-1]*(f[cnt]-f[i]));
        cout<<ans;
        return 0;
    }

    2. 列车调度
    (manage.cpp/c/pas)
     【 问题描述 】
     有N辆列车,标记为1,2,3,…,N。它们按照一定的次序进站,站台共有K个轨道,轨道遵从 先进先出的原则。列车进入站台内的轨
    道后可以等待任意时间后出站,且所有列车不可后退。现在要使出站的顺序变为N,N-1,N-2,…,1,询问K的最小值是多少。

    【输入格式】 】
     文件名为manage.in。
     输入共2行。
     1 1个正整数N,表示N辆列车。
     第 2 行包含N个正整数,为1至N的一个排列,
    表示进站次序。

    【输出格式】 】
     文件名为manage.out。
     输出共1行,包含1个整数,表示站台内轨
    道数K的最小值。

    【输入输出样例2 2】 】
    manage.in manage.out
    9
    1 3 2 4 8 6 9 5 7
    5

    最长上升子序列

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<vector>
    #include<queue>
    #include<math.h>
    using namespace std;
    int maxn,n,a[100009],B[100009],cnt;
    int find(int x)
    {
        int l,r,mid;
        l=0,r=cnt;
        while(l<=r)
        {
            mid=(l+r)/2;
            if(B[mid]>=x)    r=mid-1;
            else l=mid+1;
        }
        return l;
    }
    int main()
    {
        freopen("manage.in","r",stdin);
        freopen("manage.out","w",stdout);
        scanf("%d",&n);
        for(int i=1;i<=n;i++)    scanf("%d",&a[i]);
        
        B[0]=-1;cnt=0;
        for(int i=1;i<=n;i++)
        {
            if(a[i]>B[cnt])    B[++cnt]=a[i];
            else{
                int t=find(a[i]);
                B[t]=a[i];
            }
        }
        cout<<cnt;
        return 0;
    }

    3. 保留道路
    (road.cpp/c/pas)
     【 问题描述 】
     很久很久以前有一个国家,这个国家有N个城市,
    城市由1,2,3,…,N标号,城市间有M条双向道路,每
    条道路都有两个属性g和s,两个城市间可能有多条
    道路,并且可能存在将某一城市与其自身连接起来
    的道路。后来由于战争的原因,国王不得不下令减
    小花费从而关闭一些道路,但是必须要保证任意两
    个城市相互可达。
     道路花费的计算公式为wG*max{所有剩下道路的属
    性g}+wS*max{所有剩下道路的属性s},其中wG和
    wS是给定的值。国王想要在满足连通性的前提下使
    这个花费最小,现在需要你计算出这个花费。

    【输入格式】 】
     输入文件名为road.in。
     第一N和M。
     第二行包含两个正整数wG和wS。
     后面的M行每行描述一条道路,包含四个正
    整数u,v,g,s,分别表示道路连接的两个城市
    以及道路的两个属性。
    【 【输出格式】 】
     输出文件名为road.out。
     输出一个整数,表示最小花费。若无论如
    何不能满足连通性,输出-1。
    【 【输入输出样例】 】
    road.in road.out
    3 3
    2 1
    10 15
    2 4 20
    1 3 5 1
    30
    【 数据规模与约定】 】
     1,M≤20;
     311  50%的数据,N≤200,M≤50;
     对于100%的数据,N≤400,M≤50000,
    wG,wS,g,s≤1000000000。

    50分思路:  比较简单的做法。

      (1)先从小到大枚举maxg

      (2)对于每一个maxg,选出所有满足g<=maxg的边,按照s从小到大排序,克鲁斯卡尔建最小生成树。得到maxs,  总答案和ans取max。

        复杂度大概是m*m

    #include<iostream>
    #include<queue>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<math.h>
    using namespace std;
    struct node{
        int u,v;
        int g,s;
    }a[50009],b[50009];
    int n,m,Wg,Ws;
    int G[50009],f[500];
    long long  INF=1LL << 62,ans=1LL << 62;
    bool vis[500];
    bool cmp(node x,node y)
    {    return x.s<y.s; }
    int find(int x)
    {
        while(x!=f[x])
            x=f[x]=f[f[x]];
        return x;
    }
    void bing(int x,int y)
    {
        int f1=find(x),f2=find(y);
        f[f1]=f2;
    }
    int main()
    {
    
        freopen("road.in","r",stdin);
        freopen("road.out","w",stdout);
        scanf("%d%d",&n,&m);
        scanf("%d%d",&Wg,&Ws);
        
        for(int i=1,u,v,g,s;i<=m;i++)
        {
            scanf("%d%d%d%d",&u,&v,&g,&s) ;
            a[i].u=u,a[i].v=v,a[i].g=g,a[i].s=s;
            G[i]=g;
        }
        
        sort(G+1,G+1+m);
        sort(a+1,a+1+m,cmp);    
        
        
        for(int k=1;k<=m;k++)
        {        
            int maxG=G[k],cnt=0,maxS,tot=n;    
            for(int i=1;i<=n;i++)    f[i]=i;
            for(int i=1;i <= m;i++)
                if(a[i].g <= maxG )
                    b[++cnt]=a[i];    
            for(int i=1;i<=cnt;i++)
            {
                int f1,f2;
                f1=find(b[i].u),f2=find(b[i].v);
                if(f1!=f2)
                {
                    bing(f1,f2),tot--;
                    maxS=b[i].s;
                }
                
                if(Wg*1LL*maxG+1LL*Ws*maxS > ans)    continue;
                
                if(tot==1)
                {
                    ans=min(ans,1LL*Wg*maxG+1LL*Ws*maxS);
                    break;
                }
            }        
        }
        if(ans==INF )    cout<<-1;
        else cout<<ans;
        return 0;
    }
    50分

     100分思路:

      上一个做法时,每枚举一个maxg都要建一次树,选边的时候要把所有的边都要扫一遍,而造成了很多重复的地方

      ,那些就想办法,把选边的复杂度降低。 

      (1)以g为第一关键字,s为第二关键字排序。(很奇妙)

      (2)再建树的时候维护一个数组表示,当前为止最优答案的边集(集合按照s排序)。每枚举一个g增加了一条边,把这条边插到集合中。

      (3)再去建树,如果能建成树更新答案。

    #include<iostream>
    #include<queue>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<math.h>
    using namespace std;
    typedef long long LL;
    struct node{
        int u,v;
        LL g,s;
    }a[50009],b[50009];
    int n,m,Wg,Ws;
    int G[50009],f[500],to[50009];
    long long  INF=1LL << 62,ans=1LL << 62;
    bool cmp(node x,node y)
    {
        if(x.g==y.g) return x.s<y.s;
        else return x.g<y.g;    
    }
    int find(int x)
    {
        while(x!=f[x])
            x=f[x]=f[f[x]];
        return x;
    }
    int main()
    {
    
        freopen("road.in","r",stdin);
        freopen("road.out","w",stdout);
        scanf("%d%d",&n,&m);
        scanf("%d%d",&Wg,&Ws);
        
        for(int i=1,u,v,g,s;i<=m;i++)
        {
            scanf("%d%d%d%d",&u,&v,&g,&s) ;
            a[i].u=u,a[i].v=v,a[i].g=g,a[i].s=s;    
        }
        sort(a+1,a+1+m,cmp);
        
        int tot=0,cnt;
        for(int k=1;k<=m;k++)
        {
            if(a[k].s*Ws+a[k].g*Wg > ans)    continue;
            for(int i=1;i<=n;i++)    f[i]=i;
            int i;
            for( i=tot;i>=1;i--)
                if(a[to[i]].s>a[k].s)    to[i+1]=to[i];
                else break;
            tot++,to[i+1]=k;
            cnt=0;
            for( i=1;i<=tot;i++)
            {
                int f1,f2;
                f1=find(a[to[i]].u),f2=find(a[to[i]].v);
                if(f1!=f2)
                {
                    f[f1]=f2;
                    to[++cnt]=to[i];                
                }            
            }
            if(cnt==n-1)        
                ans=min(ans,a[k].g*Wg+a[to[cnt]].s*Ws);    
            tot=cnt;    
        }
        
        if(ans==INF )    cout<<-1;
        else cout<<ans;
        return 0;
    }
    100分
  • 相关阅读:
    js获取客户端IP及地理位置
    跟SAP系统集成的Android应用
    关于刘冬大侠Spring.NET系列学习笔记3的一点勘正
    设置浏览器全屏模式
    一个模拟"显示桌面.scf"程序的JS小函数
    网站整体变灰(黑白、置灰)原理
    苹果手机上input的button按钮颜色显示问题
    用Python做数据清洗:采集几百个xls或csv中的数据并汇总
    用ISO-8859-1解决Python 'utf-8' codec can't decode bytes in position 924-925问题
    Python批量转换子文件夹下的文件编码
  • 原文地址:https://www.cnblogs.com/CLGYPYJ/p/7403469.html
Copyright © 2011-2022 走看看