河南省第九届大学生程序设计竞赛 题解

A 表达式求值



Description

假设表达式定义为:
1. 一个十进制的正整数 X 是一个表达式。
2. 如果 X 和 Y 是 表达式,则 X+Y, X*Y 也是表达式; *优先级高于+.
3. 如果 X 和 Y 是 表达式,则 函数 Smax(X,Y)也是表达式,其值为:先分别求出 X ,Y
值的各位数字之和,再从中选最大数。
4.如果 X 是 表达式,则 (X)也是表达式。
例如:
表达式 12*(2+3)+Smax(333,220+280) 的值为 69。
请你编程,对给定的表达式,输出其值。

Input

第一行: T 表示要计算的表达式个数 ( 1T10 1≤T≤10
接下来有 T 行, 每行是一个字符串,表示待求的表达式,长度<=1000

Output

对于每个表达式,输出一行,表示对应表达式的值。

Sample Input

3
12+2*3
12*(2+3)
12*(2+3)+Smax(333,220+280)

Sample Output

18
60
69


解题思路:
     经典模拟题,建两个栈,将符号和数字分别入栈,根据符号优先级进行出站运算操作。这里加了一个Smax(X,Y)函数,内部运算我也用了栈,处理起来会复杂一些。具体的细节见代码。

代码:
#include <iostream>
#include<bits/stdc++.h>

using namespace std;

stack<int>q,r;
stack<char>w;
char s[1100];

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        scanf("%s",s);
        int n=strlen(s);
        s[n]=')';
        w.push('(');
        for(int i=0;i<=n;i++)
        {
            if(s[i]<='9'&&s[i]>='0')//将数值压入数值栈中
            {
                int num=0;
                while(i<n&&s[i]<='9'&&s[i]>='0')
                {
                    num=num*10+s[i]-'0';
                    i++;
                }
                q.push(num);
                i--;
            }
            else//如果是符号
            {
                if(s[i]=='+')   w.push('+');//加法入符号栈
                if(s[i]=='*')   w.push('*');//乘法入符号栈
                if(s[i]=='(')   w.push('(');//左括号入符号栈
                if(s[i]=='S')//Smax函数入符号栈
                {
                    w.push('S');
                    i+=4;
                }
                if(s[i]==',')//逗号入符号栈
                {
                    w.push(',');
                }

                if(s[i]==')')//如果遇到右括号,说明括号中的运算完成或者Smax函数完成,开始出栈进行运算
                {
                    char c;
                    int num1=q.top();//数值出栈
                    q.pop();
                    r.push(num1);//放入处理栈
                    while(1)
                    {
                        c=w.top();//符号出站
                        w.pop();
                        if(c==','||c=='('||c=='S')  break;//遇到相对应的符号,跳出循环
                        num1=q.top();//数值出栈
                        q.pop();
                        //现在符号只剩下+和*,由于优先级的问题,需要用栈处理
                        if(c=='+')//如果是加法,入栈
                        {
                            r.push(num1);
                        }
                        else if(c=='*')//如果是乘法,再出栈一个数,两个数相乘结果入栈
                        {
                            int num2=r.top();
                            r.pop();
                            r.push(num2*num1);
                        }
                    }
                    num1=0;
                    while(!r.empty())//将处理栈中的值全部相加就是加法和乘法的结果
                    {
                        num1+=r.top();
                        r.pop();
                    }
                    if(c=='(')//这是跳出的符号是'(',说明只是个括号运算,将值直接入栈即可
                    {
                        q.push(num1);
                    }
                    else if(c==',')//如果是跳出的符号是',',说明Smax函数,已经执行了右半边运算,我们将左半边运算也进行处理,具体细节与上述类似
                    {
                        char cc;
                        int num3=q.top();
                        q.pop();
                        r.push(num3);
                        while(1)
                        {
                            cc=w.top();
                            w.pop();
                            if(cc=='S')  break;//只可能是'S'
                            num3=q.top();
                            q.pop();
                            if(cc=='+')
                            {
                                r.push(num3);
                            }
                            else if(cc=='*')
                            {
                                int num4=r.top();
                                r.pop();
                                r.push(num3*num4);
                            }
                        }
                        num3=0;//num1,num3,分别是Smax函数的两个参数
                        while(!r.empty())
                        {
                            num3+=r.top();
                            r.pop();
                        }
                        int max1=0,max2=0;//处理Smax函数
                        while(num1!=0)
                        {
                            max1+=num1%10;
                            num1/=10;
                        }
                        while(num3!=0)
                        {
                            max2+=num3%10;
                            num3/=10;
                        }
                        q.push(max(max1,max2));//结果入栈
                    }
                }
            }
        }
        cout<<q.top()<<endl;//最后栈中只剩下一个值,就是运算的结果
        while(!q.empty())   q.pop();
        while(!w.empty())   w.pop();
    }
}



B 宣传墙


Description

ALPHA 小镇风景美丽,道路整齐,干净,到此旅游的游客特别多。CBA 镇长准备在一条道路南
面 4*N 的墙上做一系列的宣传。为了统一规划,CBA 镇长要求每个宣传栏只能占相邻的两个方格
位置。但这条道路被另一条道路分割成左右两段。CBA 镇长想知道,若每个位置都贴上宣传栏,
左右两段各有有多少种不同的张贴方案。
例如:
N=6,M=3, K=2, 左,右边各有 5 种不同的张贴方案

Input

第一行: T 表示以下有 T 组测试数据 ( 1≤T ≤8 )
接下来有T行, 每行三个正整数 N M K 分别表示道路的长度,另一条道路的起点和宽度
(1≤ N ,M ≤ 1 000 000, 1≤ K ≤ 100000)

Output

每组测试数据,输出占一行:两个整数,分别表示左右两段不同的张贴方案数。由于方案总数
可能很大,请输出对 997 取模后的结果。

Sample Input

2
6 3 2
5 3 2

Sample Output

5 5
5 1


解题思路:
       用dp解决,需要用前缀和优化。详见代码

代码:
#include <iostream>
#include<bits/stdc++.h>

using namespace std;
const int MOD=997;
int d[1100000],s[2],q[2]={3,2};


/*
d[i]为长度i的方案总数;
q[i]为长度为i,并且不可被纵向分开的方案总数(不能由两种更小的长度拼接起来)
很容易得到:
    d[i]=SUM(q[j]*d[i-j]),j<i
现在有两个问题,首先是如何求得q[i],其次递推式的复杂度为O(n²),很明显是不满足这题的数据量的。

我们先考虑第一个问题,多次尝试画出不能分开的方案数(很好找规律),我们可以总结出一个规律。
     i=1,q[i]=1;
     i=2,q[i]=4;
     i>3,当i为奇数时,q[i]=2;当i为偶数时,q[i]=3;

现在我们考虑第二个问题,由于s[i]大多数情况下只有奇偶之分
                设sum=d[1]+d[2]+...+d[i-1]
                s[0]=d[2]+d[4]+...+d[i-i&1]
                s[1]=d[1]+d[3]+...+d[(i-1)|1]
根据之前分析可以得到:
                d[i]=d[i-1]*1+d[i-2]*5+d[i-3]*2+...+d[1]*q[(i-1)%2]+d[0]*q[i%2]
由上述定义可以转化成:
                d[i]=sum*2+s[i%2]+(1-2)*d[i-1]+(4-3)*d[i-2]+q[i%2]
*/
int main()
{
    int sum=6;
    d[1]=1;
    d[2]=5;
    s[1]=1;
    s[0]=5;
    for(int i=3;i<=1000000;i++)
    {
        d[i]=(sum*2+s[i%2]-d[i-1]+d[i-2]+MOD+q[i%2])%MOD;
        s[i%2]=(s[i%2]+d[i])%MOD;
        sum=(sum+d[i])%MOD;
    }

    int T,n,m,k;
    cin>>T;
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&k);
        cout<<d[m-1]<<" "<<d[n-m-k+1]<<endl;
    }
}


C 信道安全

Description

Alpha 机构有自己的一套网络系统进行信息传送。情报员 A 位于节点 1,他准备将一份情报
发送给位于节点 n 的情报部门。可是由于最近国际纷争,战事不断,很多信道都有可能被遭到监
视或破坏。
经过测试分析,Alpha 情报系统获得了网络中每段信道安全可靠性的概率,情报员 A 决定选
择一条安全性最高,即概率最大的信道路径进行发送情报。
你能帮情报员 A 找到这条信道路径吗?

Input

第一行: T 表示以下有 T 组测试数据 ( 1≤T ≤8 )
对每组测试数据:
第一行: n m  分别表示网络中的节点数和信道数 (1<=n<=10000,1<=m<=50000)
接下来有 m 行, 每行包含三个整数 i,j,p,表示节点 i 与节点 j 之间有一条信道,其信
道安全可靠性的概率为 p%。 ( 1<=i, j<=n 1<=p<=100)

Output

每组测试数据,输出占一行,一个实数 即情报传送到达节点 n 的最高概率,精确到小数点后
6 位。

Sample Input

1
5 7
5 2 100
3 5 80
2 3 70
2 1 50
3 4 90
4 1 85
3 1 70

Sample Output

61.200000

解题思路:
      可以用求最短路的方法求最高概率。求由于1<=n<=10000,1<=m<=50000,节点多而边较少,是稀疏图,所以用spfa会比较好(如果dijkstra不用堆优化会超时吧。。),模板题。

代码:
#include <iostream>
#include<bits/stdc++.h>


using namespace std;
const int N=11000;
const int M=55000*2;
int n,m,head[N],cnt,vis[N];
double d[N];

struct node
{
    int v,next;
    double p;
}e[M];

void init()
{
    memset(head,-1,sizeof(head));
    cnt=0;
}

void add(int u,int v,double p)
{
    e[cnt].v=v;
    e[cnt].p=p;
    e[cnt].next=head[u];
    head[u]=cnt++;
}

double spfa()
{
    for(int i=0;i<=n;i++)
    {
        d[i]=0;
        vis[i]=0;
    }
    queue<int>q ;
    q.push(1);
    vis[1]=1;
    d[1]=1;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];i+1;i=e[i].next)
        {
            int v=e[i].v;
            double p=e[i].p;
            if(d[v]<d[u]*p/100.0)
            {
                d[v]=d[u]*p/100.0;
                if(!vis[v])
                {
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
    return d[n];
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        init();
        for(int i=0;i<m;i++)
        {
            int u,v;
            double p;
            scanf("%d%d%lf",&u,&v,&p);
            add(u,v,p);
            add(v,u,p);
        }
        printf("%.6f\n",spfa()*100);
    }
}



D 导弹发射


Description

Alpha 机构研发出一种新型智能导弹,它能够在雷达检测到的区域内,选择一条前进的路径,
击破路径上所有的目标物。
雷达位于(0,0)处,它能够检测到两条射线之间的区域(不妨设在第一象限)。
导弹一开始置放在(0,0)处,它可以在雷达能检测到的区域内先选择一个目标物击破,然后
再继续前进,选择另一个目标物击破。注意,导弹不能沿着这两条射线前进,当然也不能停在原
地。
可以假设,导弹一旦发射,其能量无比大,前进的路径无限长。
已知雷达能够检测到区域,其射线 1:ax-by=0 和射线 2:cx-dy=0。Alpha 机构的总指挥希望
在发现目标群的第一时刻,计算出一条可以击破最多目标物的路径。

Input

第一行: T 表示以下有 T 组测试数据(1≤T ≤8)
对每组测试数据:
第 1 行: n 表示目标物的个数
第 2 行: a b c d 代表两条射线的斜率分别是 a/b 和 c/d。
接下来有 n 行,每行 2 个正整数 xi yi 即第 i 个目标物的坐标。
(1) n<=10^5 0<=a, b, c, d<=10^5 a 和 b 不会同时为 0,c 和 d 不会同时为 0;
(2) 0<= xi , yi <=10^6 i=1,…..,n

Output

每组测试数据,输出占一行,即导弹能击破的最多目标数。

Sample Input

1
15
1 3 2 1
3 1
6 2
4 2
2 5
4 5
6 6
3 4
1 6
2 1
7 4
9 3
5 3
1 3
15 5
12 4

Sample Output

4


解题思路:
     首先,我们只需要考虑在曲线之内的点。然后思考,如何判断导弹是前进的?(这个问题在比赛的时候一直困扰我)我们将两条射线看成x轴和y轴进行坐标变换,有了新的坐标后,很容易可以判断前进的情况(x递增,y递增)。变换之后用nlogn的LIS求解即可。这里要注意一个问题,当x轴不变,y轴增大时,LIS有可能将其统计在内。我们在排序时设置,当x相等时y从大到小排序,可以解决上述问题。
     这题的题面其实表达的不是很清楚,比如是否有多个目标在同一位置,两条射线的相对位置是否固定。。。然而题目在不考虑这些因素的情况下都能A。。。

代码:
#include <iostream>
#include<bits/stdc++.h>

using namespace std;
const int N=110000;

struct node
{
    double x,y;
}a[N],b[N];

bool cmp(node a,node b)//先按x从小到大排序,如果x相等按y从大到小排序,这样排除了沿y轴前进的情况
{
    if(a.x==b.x)    return a.y>b.y;
    return a.x<b.x;
}

int Search(int num,int low,int high)
{
    int mid;
    while(low<=high)
    {
        mid=(low+high)/2;
        if(a[num].y>b[mid].y) low=mid+1;
        else    high=mid-1;
    }
    return low;
}

int dp(int n)//LIS nlogn模板
{
    int i,len,pos;
    b[1].x=a[1].x;
    b[1].y=a[1].y;
    len=1;
    for(int i=2;i<=n;i++)
    {
        //两个点在同一位置的情况,数据中没有
        //if(a[i].y>b[len].y&&a[i].x>b[len].x||a[i].x==b[len].x&&a[i].y==b[len].y)
        if(a[i].y>b[len].y&&a[i].x>b[len].x)
        {
            len=len+1;
            b[len].y=a[i].y;
            b[len].x=a[i].x;
        }
        else
        {
            pos=Search(i,1,len);
            b[pos].y=a[i].y;
            b[pos].x=a[i].x;
        }
    }
    return len;
}

int main()
{
    int T,n;
    double a1,b1,c1,d1;
    cin>>T;
    while(T--)
    {
        cin>>n;
        cin>>a1>>b1>>c1>>d1;
        //保证c1/d1射线在a1/b1上面,数据中不存在相反情况
        /*if(b1==0||c1==0||(b1!=0&&d1!=0&&c1/d1<a1/b1))
        {
            swap(a1,c1);
            swap(b1,d1);
        }*/
        int cnt=0;
        for(int i=1;i<=n;i++)
        {
            double x,y;
            scanf("%lf%lf",&x,&y);
            //如果点在两个射线之内
            if(y*d1<x*c1&&x*a1<y*b1)
            {
                cnt++;
                //坐标变换
                a[cnt].x=(x-y*d1/c1)*c1/sqrt(c1*c1+d1*d1);
                a[cnt].y=(y-x*a1/b1)*b1/sqrt(a1*a1+b1*b1);
            }
        }
        sort(a+1,a+cnt+1,cmp);
        cout<<dp(cnt)<<endl;
    }
}


E 机器设备


Description

Alpha 公司设计出一种节能的机器设备。它的内部结构是由 N 个齿轮组成。整个机器设备有
一个驱动齿轮,当启动它时,它立即按 10,000 圈/小时转速顺时针转动,然后它又带动与它相切
的齿轮反方向,即逆时针转动。齿轮之间互相作用,每个齿轮都可能驱动着多个齿轮,最终带动
一个工作齿轮完成相应的任务 。
在这套设备中,记录了每个齿轮的圆心坐标和齿轮半径。已知驱动齿轮位于(0,0),最终的
工作齿轮位于(Xt, Yt)。
Alpha 公司想知道传动序列中所有齿轮的转速。所谓传动序列,即能量由驱动齿轮传送,最
后到达工作齿轮的过程中用到的所有齿轮。能量传送过程是,在一个半径为 R,转速为 S 圈/每小
时的齿轮的带动下,与它相切的半径为 R’的齿轮的转速为-S*R/R` 转/小时。负号的意思是, 表
示按反方向转动。
已知,机器设备中除了驱动齿轮以外,所有齿轮都可能被另外某个齿轮带动,并且不会出现
2 个不同的齿轮带动同一个齿轮的情况。
你的任务是计算整个传动序列中所有齿轮的能量之和。即所有齿轮转速的绝对值之和。

Input

第一行: T 表示以下有 T 组测试数据(1≤T ≤8)
对每组测试数据:
第 1 行: N Xt Yt (2≤N ≤1100)
接下来有 N 行, Xi Yi Ri 表示 N 个齿轮的坐标和半径 i=1,2,….,N
( -5000 ≤Xi ,Yi ≤ 5000 3 ≤ Ri ≤ 1000 )

Output

第一行: T 表示以下有 T 组测试数据(1≤T ≤8)
对每组测试数据:
第 1 行: N Xt Yt (2≤N ≤1100)
接下来有 N 行, Xi Yi Ri 表示 N 个齿轮的坐标和半径 i=1,2,….,N
( -5000 ≤Xi ,Yi ≤ 5000 3 ≤ Ri ≤ 1000 )

Sample Input

1
4 32 54
0 30 20
0 0 10
32 54 20
-40 30 20

Sample Output

20000

解题思路
     对相邻的齿轮建边,然后dfs搜索最终的齿轮,将路径上的齿轮速度相加即可。

代码:
#include <iostream>
#include<bits/stdc++.h>

using namespace std;

const int N=5000;
const int M=100000;

int n,head[N],cnt,ed,bg,r[N],x[N],y[N],xt,yt;
double ans;
int pre[N];
struct node
{
    int v,next;
}e[M];

void init()
{
    memset(head,-1,sizeof(head));
    cnt=0;
    memset(pre,-1,sizeof(pre));
}

void add(int u,int v)
{
    e[cnt].v=v;
    e[cnt].next=head[u];
    head[u]=cnt++;
}

int dfs(int t,int fa)
{
    pre[t]=fa;
    if(t==ed)
    {
        for(int i=t;i!=-1;i=pre[i])
        {
            ans+=10000.0*(double)r[bg]/r[i];
        }
        return 1;
    }
    for(int i=head[t];i+1;i=e[i].next)
    {
        int u=e[i].v;
        if(u==fa)    continue;
        if(dfs(u,t))    return 1;
    }
    return 0;
}

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        scanf("%d%d%d",&n,&xt,&yt);
        for(int i=0;i<n;i++)
        {
            scanf("%d%d%d",&x[i],&y[i],&r[i]);
            if(x[i]==0&&y[i]==0)    bg=i;
            if(x[i]==xt&&y[i]==yt)  ed=i;
        }
        init();
        for(int i=0;i<n;i++)
            for(int j=i+1;j<n;j++)
            {
                if((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])==(r[i]+r[j])*(r[i]+r[j]))//如果两个齿轮相邻,建边
                {
                    add(i,j);
                    add(j,i);
                }
            }
        ans=0.0;
        dfs(bg,-1);
        printf("%d\n",(int)ans);
    }
}


F Decimal integer conversion

Description

XiaoMing likes mathematics, and he is just learning how to convert numbers between different
bases , but he keeps making errors since he is only 6 years old. Whenever XiaoMing converts a
number to a new base and writes down the result, he always writes one of the digits wrong.
For example , if he converts the number 14 into binary (i.e., base 2), the correct result should be
"1110", but he might instead write down "0110" or "1111". XiaoMing never accidentally adds or
deletes digits, so he might write down a number with a leading digit of " 0" if this is the digit she
gets wrong.
Given XiaoMing 's output when converting a number N into base 2 and base 3, please determine
the correct original value of N (in base 10). (N<=10^10)
You can assume N is at most 1 billion, and that there is a unique solution for N.

Input

The first line of the input contains one integers T, which is the nember of test cases (1<=T<=8)
Each test case specifies:
* Line 1: The base-2 representation of N , with one digit written incorrectly.
* Line 2: The base-3 representation of N , with one digit written incorrectly.

Output

For each test case generate a single line containing a single integer ,  the correct value of N

Sample Input

1
1010
212

Sample Output

14


解题思路:
      暴力枚举出2进制和3进制的所有情况,然后对比,同时都存在数就是正确答案。

代码:
#include <iostream>
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1100;
ll b[N],a[N];
char b2[N],b3[N];

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        scanf("%s%s",b2,b3);
        int len2=strlen(b2);
        int len3=strlen(b3);
        ll base2=0,base3=0;
        for(int i=0;i<len2;i++)
        {
            base2=base2*2+b2[i]-'0';
        }
        for(int i=0;i<len3;i++)
            base3=base3*3+b3[i]-'0';
        ll t=1;
        for(int i=len2-1;i>=0;i--)
        {
            if(b2[i]=='0')   a[i]=base2+t;
            else    a[i]=base2-t;
            t*=2;
        }
        t=1;
        int cnt=0;
        for(int i=len3-1;i>=0;i--)
        {
            if(b3[i]=='0')
            {
                b[cnt++]=base3+t;
                b[cnt++]=base3+2*t;
            }
            if(b3[i]=='1')
            {
                b[cnt++]=base3+t;
                b[cnt++]=base3-t;
            }
            if(b3[i]=='2')
            {
                b[cnt++]=base3-t;
                b[cnt++]=base3-t*2;
            }
            t*=3;
        }
        for(int i=0;i<len2;i++)
            for(int j=0;j<cnt;j++)
            {
                if(a[i]==b[j])  cout<<a[i]<<endl;
            }
    }
}



G Prototypes analyze


Description

ALpha Ceiling Manufacturers (ACM) is analyzing the p roperties of its new series of Incredibly
Collapse-Proof Ceilings (ICPCs). An ICPC consists of n layers of material, each with a different
value of collapse resistance (measured as a positive integer). The analysis ACM wants to run will
take the collapse-resistance values of the layers, store them in a binary search tree, and check
whether the shape of this tree in any way correlates with the quality of the whole construction.
Because, well, why should it not?
To be precise, ACM takes the collapse-resistance values for the layers, ordered from the top layer
to the bottom layer, and inserts them one-by-one into a tree. The rules for inserting a value v are:
• If the tree is empty, make v the root of the tree.
• If the tree is not empty, compare v with the root of the tree. If v is smaller, insert v into the left
subtree of the root, otherwise insert v into the right subtree.
ACM has a set of ceiling prototypes it wants to analyze by trying to collapse them. It wants to take
each group of ceiling prototypes that have trees of the same shape and analyze them together.
For example , assume ACM is considering five ceiling prototypes with three layers each, as
described by Sample Input 1 and shown in Figure C.1. Notice that the first prototype’s top layer
has collapseresistance value 2, the middle layer has value 7, and the bottom layer has value 1. The
second prototype has layers with collapse-resistance values of 3, 1, and 4 – and yet these two
prototypes induce the same tree shape, so ACM will analyze them together.
Given a set of prototypes, your task is to determine how many different tree shapes they induce.

Input

The first line of the input contains one integers T, which is the nember of test cases (1<=T<=8).
Each test case specifies:
* Line 1: two integers n (1 ≤ n ≤ 50), which is the number of ceiling prototypes to analyze,
and k (1  ≤  k ≤  20), which is the number of layers in each of the prototypes.
*T he next n lines describe the ceiling prototypes. Each of these lines contains k distinct
integers ( between 1 and 10 6 , inclusive ) , which are the collapse-resistance values of the
layers in a ceiling prototype, ordered from top to bottom.

Output

For each test case generate a single line containing a single integer that is the number of different tree
shapes.

Sample Input

1
5 3
2 7 1
1 5 9
3 1 4
2 6 5
9 7 3

Sample Output

4

解题思路:
      对于先对每棵树用dfs建树并存储,然后用dfs2比较两棵树的树形是否一样。

代码:
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
const int N=110;
struct node
{
    int val,l,r;
}a[N][N];

int cnt,n,k,v[N];

void dfs(int c,int u,int t)//建树
{
    if(a[c][u].val==-1)
    {
        a[c][u].val=t;
        a[c][u].l=a[c][u].r=-1;
        cnt++;
        return ;
    }
    if(a[c][u].val>t)
    {
        if(a[c][u].l==-1)
        {
            a[c][u].l=cnt;
            dfs(c,cnt,t);
        }
        else
        {
            dfs(c,a[c][u].l,t);
        }
    }
    else
    {
        if(a[c][u].r==-1)
        {
            a[c][u].r=cnt;
            dfs(c,cnt,t);
        }
        else
        {
            dfs(c,a[c][u].r,t);
        }
    }
}

int dfs2(int x,int t1,int y,int t2)//比较两棵树形是否相同
{
    if((t1==-1&&t2!=-1)||(t1!=-1&&t2==-1))  return 0;
    if(t1==-1&&t2==-1)  return 1;
    return dfs2(x,a[x][t1].l,y,a[y][t2].l)&&dfs2(x,a[x][t1].r,y,a[y][t2].r);
}

int ok(int x,int y)
{
    return dfs2(x,0,y,0);
}

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        scanf("%d%d",&n,&k);
        for(int i=0;i<n;i++)
        {
            cnt=0;
            for(int j=0;j<k;j++)
            {
                a[i][j].val=-1;
                int t;
                scanf("%d",&t);
                dfs(i,0,t);
            }
        }
        int ans=0;
        memset(v,0,sizeof(v));
        for(int i=0;i<n;i++)
        {
            if(v[i])    continue;
            ans++;
            for(int j=i+1;j<n;j++)
            {
                if(ok(i,j)) v[j]=1;
            }
        }
        cout<<ans<<endl;
    }
}







  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
国际程序设计大赛的作品欣赏 1、 先来第一个: 一段纯 3D 的 DOS 动画,据说是获一等奖的作品。虽然它不是最精美的, 但是当你得知它只有 4K 时,会不会立刻疯死掉呢? 附件:3ddemo.com 2、 再来一个: 幽灵古堡 farb-rausche 64.0 KB (65,536 字节) 恰好 65536 字节,显然是参赛作品。它非常漂亮(利用了 Direct3D),更让人惊奇的是只有 64K!而更让人震惊的是,如果不压缩的话它的数据大小是 1.6G!再体会一次“奇迹”! 附件:castle.exe 3、 再来一个: 死亡阴影 64.0 KB (65,536 字节) 附件:death.exe 4、 火域幻境 73.0 KB (74,752 字节) 虽然大小超过了 64K 的限制,但是它的效果可称为程序中的艺术品了! 附件:fire.exe 5、 fr-016 farb-rausche 16 字节 (16 字节) Let's rock hard!一个 DOS 里的小动画。看上去似乎没有什么特别,但是如果看到它的大小(16 字节),什么感觉????? 附件:fr-016.com 6、 第七天堂 Exceed 64.0 KB (65,536 字节) 由于参赛的要求是在 64K 之内即可,不少参赛者未免会有不到 65536 字节就有吃亏的感觉。 这是个 恰好 64K 的作品,可能利用了 DirectX 引擎,效果很好。 附件:heaven7.exe 7、 金属迷城 6.00 KB (6,144 字节) 考虑到它的大小时,你会不会体会到奇迹的含义 附件:metal.exe 8、 我要重点推荐的是这个作品fr-041_debris.exe(177K),效果是这所有作品之中最好的,一般的电脑无法流畅运行,我认为你买电脑时 可以把它带上运行一下作为一款测试工具。 附件:fr-041_debris.exe 9、 这个作品的效果和以上作品比都可名列前矛(64K),效果很好 附件:kkino64.exe 10、 这个就是传说中的25万倍压缩作品,prophecy《彗星撞地球》(63.5K)2000年时的最经典力作!画面看着挺舒服。 附件:prophecy《彗星撞地球》.exe 11、 爱之记忆 12、 3D裸女 13、 卡通 14、 光影 15、 FAiRLiGHT 这是在《三角洲3大地勇士》光碟版中带有的一个DEMO,发行组织FAiRLiGHT完全用原代码写出的自己组织的DEMO演示程序, 竟然才15K大小,画面也还行,对于他们的技术我们只能感到折服!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值