2016.8.29.第39套测试题

描述(A 输入文件 : A.input 输出文件 : A.output)
一个城市的构成是一颗n 个节点的树(2 ≤ n ≤ 200), 现在需要在树中找出两条不相交的路
径(即两条路径不能有重边也不能有重点),使得路径的长度的乘积最大。

解析:

这道题很简单,因为说了是颗无环树,然后在树上找两条线不想交,乘积最大。很容易想到,枚举边,然后从两个断点的子树分别找两条最长路径,就是最大值。找最长路径方法呢,因为数据很小,可以直接暴力出所有儿子的最深长度,然后选两个最长的相加。当然更简单的就是先找个点的最深到i,再从i搜条最长路到j,那么i,j就是最长的路径。

代码:

#include<iostream>
#include<cstdio>
#include<fstream>
#include<cstring>
#include<cmath>
using namespace std;
ifstream fin ("A.input");
ofstream fout ("A.output");
struct stu{
    int x,y;
}con[205];
int a,b,f[205][205],n,ans,g[205][205];
bool use[205];
int find(int v)
{
    int ma=0;
    use[v]=false;
    for(int i=1;i<=n;i++)
    if(f[v][i]&&use[i]) {g[v][i]=1+find(i); ma=max(ma,g[v][i]);}
    return ma;
}
int main()
{
    fin>>n;
    for(int i=1;i<=n-1;i++)
    {
        fin>>a>>b;
        f[a][b]=f[b][a]=1;
        con[i].x=a;
        con[i].y=b;
    }
    for(int i=1;i<=n-1;i++)
    {
        memset(use,true,sizeof(use));
        memset(g,0,sizeof(g));
        int q3=0;
        a=con[i].x;
        b=con[i].y;
        f[a][b]=f[b][a]=0;
        use[a]=use[b]=false;
        int q1=find(a);
        for(int i=1;i<=n;i++) 
        if(g[a][i]>=q3) q1=q3,q3=g[a][i];
        else if(g[a][i]>q1) q1=g[a][i];//少了这一步就少了90分 
        q1+=q3,q3=0;
        int q2=find(b);
        for(int i=1;i<=n;i++) 
        if(g[b][i]>=q3) q2=q3,q3=g[b][i];
        else if(g[b][i]>q2) q2=g[b][i];//
        q2+=q3;
        if(q1*q2>ans) ans=q1*q2;
        f[a][b]=f[b][a]=1;
    }
    fout<<ans<<endl;
    return 0;
}

错因:

找两条最长的子路时,比第一短第二长的时候没有算进去。

描述(B 输入文件 : B.input 输出文件 : B.output)
有n 个人需要看医生, 其中第i 个人需要看医生的次数是ai, 一开始从1 到n 依次排列组成
一个等待队伍, 每个人依次看医生, 那么每个人看完医生有两种情况, 第一种情况:他
已经看够他需要看医生的次数,那么他会离开。第二种情况:他还需要看医生,那么他就
会选择重新站在队伍的最后。选择医生想知道,当他看过k 次病人之后,这个等待队伍是
什么样。

解析:

这道题也很简单,就是k的问题,k 的范围是1e14过于的大了。所以需要把k的范围降下来,可以降到1e5内。如何降,其实就是找出医生在第几轮的时候结束看病。

代码:

#include<iostream>
#include<cstdio>
#include<fstream>
#include<algorithm>
#define ll long long
using namespace std;
int tot,g[100005],a[100005],b[100005],n,m;
struct stu{
    int num;
    ll sum;
}c[100005];
ll k,q,s;
int main()
{
    freopen("B.input","r",stdin);
    freopen("B.output","w",stdout);
    scanf("%d %I64d",&n,&k);//输入的时候用的d,我操 
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        b[i]=a[i];
    }
    sort(b+1,b+n+1);
    for(int i=1;i<=n;i++)
    if(b[i]!=b[i-1])
    {
        tot++;
        c[tot].num++;
        c[tot].sum=b[i];
    }
    else c[tot].num++;
    tot=0,m=n;
    while(q<k)
    {
        tot++;
        q=(ll)(q+(c[tot].sum-c[tot-1].sum)*m);
        m=m-c[tot].num;
    }
    m+=c[tot].num;
    k=(ll)(k-(q-(c[tot].sum-c[tot-1].sum)*(m)));
    s=k/m+c[tot-1].sum;//之前漏了这两部 
    k=k%m;//差值并不是1 
    for(int i=1;i<=n;i++)
    {
        if(a[i]>s&&m) 
          {
            if(k<=0)
            {m--,printf("%d",i);
             if(m>0) printf(" ");}
            else {
                   if(a[i]>s+1) g[0]++,g[g[0]]=i;
                    else m--;
                 }
             k--;    
          }
    
    }
    
    for(int i=1;i<=g[0];i++)
    {
        m--,printf("%d",g[i]);
        if(m>0) printf(" ");
    }
    return 0;
}

描述(C 输入文件 : C.input 输出文件 : C.output)
有n 个任务需要你去完成,这些任务分布在3 个不同的房间,编号为1,2,3, 其中有些任务
必须在一些其他的任务完成之后才能完成。现在知道完成一个任务需要1 的时间,现在知
从房间1 到2,2 到3,3 到1 需要1 的时间,从1 到3,2 到1,3 到2 需要2 的时间。现
在你可以选择你一开始的房间,问完全所有任务的最短时间是多少,保证可以完成。

解析:

cx用暴力,直接枚举每一个房间,不停循环,有任务做,没任务下一个。正解差不多,之说用了个拓扑排序和队列,更简单了,也是循环房间。然而我一个傻逼根本没有管房间,最后TLEl 80分...感觉今天做的好垃圾,不想多说了。

代码:

#include<iostream>
#include<cstdio>
#include<fstream>
#include<cmath>
#include<queue>
#include<cstring>
#define p 100000000
using namespace std;
ifstream fin ("C.input");
ofstream fout ("C.output");
int n,c[205],deg[205],in[205],f[205][205],q[205],x,ans=p;
int move(int a,int b)
{
    if(b==a) return 0;
    if((b-a)==1||(b-a)==-2) return 1;
    return 2;
}
queue<int>que[5];
int dp(int v)
{
    int m=0;
    int number=0;
    memcpy(deg,in,sizeof(in));
    for(int i=1;i<=n;i++) if(!in[i]) que[c[i]].push(i),number++;
    int cur=v;
    while(number)
    {
        while(!que[cur].empty())
        {
            int u=que[cur].front();
            que[cur].pop();
            number--;
            for(int i=1;i<=n;i++)
            if(f[u][i])
            {
                if(--deg[i]==0) que[c[i]].push(i),number++;
            }
        }
        if(!number) break;
        m++;
        cur++;
        if(cur>3) cur-=3;
    }
    return m+n;
}
int main()
{
    fin>>n;
    for(int i=1;i<=n;i++) fin>>c[i];
    for(int i=1;i<=n;i++) 
    {
        fin>>in[i];
        for(int j=1;j<=in[i];j++)
        {
            fin>>x;
            f[i][x]=f[x][i]=1;
        }
        
    }
    for(int i=1;i<=3;i++) 
    ans=min(ans,dp(i));
    fout<<ans<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/fisch/p/5819396.html