2011 Spring Trainning Contest SLPC

来源:互联网 发布:网络买车 编辑:程序博客网 时间:2024/05/24 06:57
额,几天没来博客了,得写点东西……
先说上周六的这场比赛。
又是水过了简单题目,稍微难的就没有想出,然后其他题目又懒得看了……
这其实是学长挂的组队赛的,题目不算很难(因为我总感觉我能做出来的就是简单题目,事实上一直如此),大部分单个人参赛的都A掉了4、5道题目,而HIT_IF、HITDPS则A掉了11道,差一道AK……两个好牛的队伍啊……

先将我A掉的题目的题解写一下:(有点废话,没A掉怎么会写题解)

HOJ 2999 AAAAHH!Overbooked!

    大水题第一:给了n条线段(开区间),求有木有两条线段有重叠部分。
    排序,然后检查即可。
#include <iostream>#define N 110using namespace std;struct data{    int start,end;    void input()    {        int st1,st2,en1,en2;        scanf("%d:%d-%d:%d", &st1, &st2, &en1, &en2);        start=st1*100+st2;        end=en1*100+en2;    }    bool operator< (const data b)const    {        return start<b.start;    }}p[N];int main(){    int n,i;    bool flag;    while(scanf("%d",&n),n)    {        for(i=0;i<n;i++)            p[i].input();        sort(p,p+n);        flag=true;        for(i=0;flag&&i<n-1;i++)            if(p[i+1].start<p[i].end)flag=false;        if(!flag)puts("conflict");        else puts("no conflict");    }    return 0;}


HOJ 3000 Betting Sets

      额,这道题是大水题第二,凭感觉这么做,但不知道具体的证明。
      给了n行m列数,对每列数进行排序,使得每行数相乘后的和最大。然后我就都按从小到大排了,应该有个证明最大数乘最大数、第二大乘第二大……最小乘最小,最终的和最大。
#include <iostream>#define N 100using namespace std;double a[N][N];int main(){    int n,m,i,j;    double ans,p;    while(scanf("%d %d",&n,&m),n||m)    {        ans=0;        for(i=0;i<n ;i++)            for(j=0;j<m;j++)                scanf("%lf",a[j]+i);        for(i=0;i<m;i++)            sort(a[i],a[i]+n);        for(i=0;i<n;i++)        {            p=1;            for(j=0;j<m;j++)                p*=a[j][i];            ans+=p;        }        printf("%.4lf\n",ans);    }    return 0;}


HOJ 3001 Counting Pixels

    大坑爹题第一。。。
    坑爹啊。。。。
    很朴素的横坐标逐一检查即可A掉,不过数据不厚道,竟然不是以3个0结尾,所以搞得我一直超时,想各种优化,差点就打表了。。。后来还是交了一个O(sqrt(n))的算法A掉了。
#include <iostream>#include <math .h>using namespace std; int main(){    long long x,y,r,p,k,i;    while(scanf("%lld %lld %lld",&x,&y,&r)==3&&(x||y||r))    {        if(r==1)        {            puts("4");            continue;        }        k=0;        for(i=r-1;i>0;i--)        {            p=(long long)ceil(sqrt(r*r-i*i));            if(p< =i)k+=p;            if(p>=i)            {                k< <=1;                k+=p*p;                break;            }        }        k*=4;        printf("%lld\n",k);    }    return 0;}


HOJ 3002 Matryoshka Dolls

大水题第三。。。。 题目大概意思是关于套娃的。。。。一层套一层。。。 做法就是求出相同型号的个数的最大值。

#include <iostream>#define N 100100using namespace std;int a[N];int main(){    int n,i,tot,ans;    while(scanf("%d",&n),n)    {        ans=0;        tot=1;        for(i=0;i<n ;i++)            scanf("%d",a+i);        sort(a,a+n);        for(i=1;i<n;i++)        {            if(a[i]==a[i-1])tot++;            else            {                if(tot>ans)ans=tot;                tot=1;            }        }        if(tot>ans)ans=tot;        printf("%d\n",ans);    }    return 0;}


HOJ 3003 Equilateral Dominoes

     这个题还是不错。
     给了n个菱形,每个菱形都是由2个带有数字的等边三角形组成,选取一部分拼接到一起,使得相邻菱形相邻的三角形数字相同。求最大的公共边。
     n的范围很小,只有6.所以算法的复杂度可以很大,关键是不好下手写这个搜索。先写了1个任意填充,最后检查的,以WA或者TLE宣告失败,然后重写了个边检查边放的,结果太杂乱,运行结果错误,也不容易debug,而宣告失败。今天再次改变策略,不管是否会重复搜索,都搜索一下,最终一0.03s宣告AC。。。
     代码很长很夸张。。。。
#include <stdio .h>const int M = 100;const int N = 6;int ans , n ;struct data{    int right, left;    bool used;    void input()    {        scanf("%d %d", &right, &left);        used = false;    }} p[ N ];struct data_map{    int x, y, color, is_to_set, tot_filled;    bool filled;    data_map& neighbor( int );    void init( int i, int j )    {        x = i;        y = j;        filled = false;    }    bool check()    {        is_to_set = -1;        tot_filled = 0;        for( int i = 0 ; i < 3 ; i ++ )        {            if( neighbor( i ).filled )            {                tot_filled ++;                if( is_to_set == -1 ) is_to_set = neighbor( i ).color;                else if( is_to_set != neighbor( i ).color ) return false;            }        }        return true;    }    bool check_color( int col )    {        if( is_to_set == -1 ) return true;        return col == is_to_set;    }    void inque( int col ,int tail );    void outque()    {        filled = false;        color  = 0;    }} map[ M ][ M ], *que[ M * M ]; data_map& data_map::neighbor(int k){    if( k == 0 ) return map[ x ][ y - 1 ];    if( k == 1 ) return map[ x ][ y + 1 ];    if( ( x ^ y ) & 1 ) return map[ x + 1 ][ y ];    return map[ x - 1 ][ y ];}void data_map::inque( int col ,int tail ){    filled = true;    color = col;    que[ tail ] = this;}void dfs(int tail, int num){    if( num > ans )    {        ans = num;/*        for( int i = 0 ; i < 40 ; i ++ )            for( int j = 0 ; j < 40 ; j ++ )            {                printf("%d " , map[ i ][ j ].color);                if( j == 39 ) puts("");            }        puts("");*/    }    for( int i = 0 ; i < n ; i ++ )    {        if( !p[ i ].used )        {            for( int j = 0 ; j < tail ; j ++ )            {                data_map &pos = *que[ j ];                if( pos.color == p[ i ].right || pos.color == p[ i ].left )                {                    for( int k = 0 ; k < 3 ; k ++ )                    {                        data_map &new_pos = pos.neighbor( k );                        if( !new_pos.filled && new_pos.check() )                        {                            for( int l = 0 ; l < 3 ; l ++ )                            {                                data_map &neigh = new_pos.neighbor( l );                                if( !neigh.filled && neigh.check() )                                {                                    if( new_pos.check_color( p[ i ].right ) && neigh.check_color( p[ i ].left ) )                                    {                                        new_pos.inque( p [ i ].right , tail );                                        neigh.inque( p[ i ].left , tail + 1);                                        p[ i ].used = true;                                         dfs( tail + 2 , new_pos.tot_filled + neigh.tot_filled + num );                                         p[ i ].used = false;                                        new_pos.outque();                                        neigh.outque();                                    }                                    else if(new_pos.check_color( p[ i ].left ) && neigh.check_color( p[ i ].right ) )                                    {                                        new_pos.inque( p [ i ].left , tail );                                        neigh.inque( p[ i ].right , tail + 1);                                        p[ i ].used = true;                                         dfs( tail + 2 , new_pos.tot_filled + neigh.tot_filled + num );                                         p[ i ].used = false;                                        new_pos.outque();                                        neigh.outque();                                    }                                }                            }                        }                    }                }            }        }    }}                         //        十个括号套着呢啊,有木有啊。。。。int main(){    while( scanf("%d", &n ), n )    {        for( int i = 0 ; i < n ; i ++ )        {            p[ i ].input();        }        for( int i = 0 ; i < M ; i ++ )            for( int j = 0 ; j < M ; j ++ )                map[ i ][ j ].init( i , j );        ans = 0;        for( int i = 0 ; i < n ; i ++ )        {            p[ i ].used = true;            map[ 20 ][ 20 ].inque( p[ i ].right , 0 );            map[ 20 ][ 21 ].inque( p[ i ].left , 1 );            dfs( 2 , 0 );            map[ 20 ][ 20 ].outque();            map[ 20 ][ 21 ].outque();            p[ i ].used = false;        }        printf("%d\n", ans);    }    return 0;}


HOJ 3004 Four Gate Push

        二维背包问题,题目还是拐了下弯,你还得先除以25、50,然后再背包,这样内存才够。。。
#include <iostream>#define M 2100#define G 1100using namespace std;int f[M][G];int main(){    int m,g,z,s,e,i,j;    while(scanf("%d %d %d %d %d",&m,&g,&z,&s,&e),m||g||z||s||e)    {        memset(f,0,sizeof(f));        m/=25;        g/=50;        for(i=4;i< =m;i++)            for(j=0;j<=g;j++)                f[i][j]=max(f[i][j],f[i-4][j]+z);        for(i=5;i<=m;i++)            for(j=1;j<=g;j++)                f[i][j]=max(f[i][j],f[i-5][j-1]+s);        for(i=2;i<=m;i++)            for(j=2;j<=g;j++)                f[i][j]=max(f[i][j],f[i-2][j-2]+e);        printf("%d\n",f[m][g]);    }    return 0;}

       水了,水了,这不是正解。正解是枚举三个的量。。。
#include <iostream>using namespace std;int main(){    int n, g, z, s, e, i, j, k;    while(scanf("%d %d %d %d %d",&n, &g, &z, &s, &e ), n | g | z | s | e )    {        int ans = 0;        for( k = 0 ; k * 50 < = n && k * 100 <= g; k ++ )            for( j = 0 ; j * 125 + k * 50 <= n && j * 50 + k * 100 <= g ; j ++ )            {                i = ( n - j * 125 - k * 50 ) / 100;                ans = max( ans , i * z + j * s + k * e );            }        printf("%d\n",ans);    }    return 0;}


HOJ 3005 Game Rigging

     知道一部分人对决的胜负情况,能否让某些人中有一个人取胜。
     DFS 啊,你手下败将能打败的就算败给你啦。。。就看你能搞定的人能不能搞定其他人拉。。有木有啊。。。。
     池子法啊,有木有啊。。。。
#include <iostream>#define N 100100#define M 100100#define K Nusing namespace std;int visit[N],tot;int fri[K];struct edge_data{    int v;    edge_data*next;}*adj[N],edge[M];void pushedge(int a,int b){    edge[tot].v=b;    edge[tot].next=adj[a];    adj[a]=&edge[tot++];}void dfs(int k){    visit[k]=1;    edge_data *temp=adj[k];    while(temp)    {        if(!visit[temp->v])dfs(temp->v);        temp=temp->next;    }}int main(){    int n,m,k,i,a,b;    while(scanf("%d %d %d",&n,&k,&m),n||m||k)    {        memset(visit,0,sizeof(visit));        memset(adj,0,sizeof(adj));        tot=0;        for(i=0;i<k ;i++)            scanf("%d",fri+i);        for(i=0;i<m;i++)        {            scanf("%d %d",&a,&b);            pushedge(a,b);        }        for(i=0;i<k;i++)            if(!visit[fri[i]])dfs(fri[i]);        for(i=0;i<n;i++)            if(!visit[i+1])break;        if(i==n)puts("yes");        else puts("no");    }    return 0;}


HOJ 3006 Highway Construction

        当时没看懂题啊,原来是求数的直径啊,大水题啊,有木有啊。。。
        随便找一点作为根进行深搜,最远的节点再作为根,再深搜,这次又得到一个最远节点,两次最远节点路上的点就是特么要修的高速公路啊。。。然后从高速公路上每个点向非高速公路上的点深搜,找一个最远距离就over啦。。。。
#include <stdio .h>#include <string .h>const int N = 100100;struct data_edge{    int v,w;    data_edge *next;}*adj[ N ], edge[ N < < 1 ];int visit[ N ], online[ N ], father[ N ];int n, maxdeep, findk, tot_edge;void push_edge( int u,int v,int w){    edge[ tot_edge ].v = v;    edge[ tot_edge ].w = w;    edge[ tot_edge ].next = adj[ u ];    adj[ u ] = &edge[ tot_edge ++ ];}void init(){    memset( adj , 0 , sizeof( adj ) );    tot_edge = 0;    for( int i = 0 ; i < n - 1 ; i ++ )    {        int a,b,w;        scanf("%d %d %d", &a, &b, &w);        push_edge(a, b, w);        push_edge(b, a, w);    }}void dfs(int k, int deep){    visit[ k ] = 1;    data_edge *temp = adj[ k ];    while( temp )    {        if( !visit[ temp->v ])        {            father[ temp->v ] = k;            dfs( temp->v , deep + temp->w);        }        temp = temp->next;    }    if( deep > maxdeep)    {        maxdeep = deep;        findk = k;    }}void solve(){    maxdeep = 0;    memset(visit , 0 ,sizeof( visit ));    dfs( 1 , 0 );    memset(visit , 0 ,sizeof( visit ));    int firstk = findk;    maxdeep = 0;    dfs( findk , 0 );    memset(visit , 0 ,sizeof( visit ));    memset(online , 0 ,sizeof( online ));    int lastk = findk;    while( lastk != firstk )    {        visit[ lastk ] = 1;        online[ lastk ] = 1;        lastk = father[ lastk ];    }    online[ lastk ] = 1;    visit[ lastk ] = 1;    maxdeep = 0;    for( int i = 1 ; i < = n ; i++ )        if( online[ i ] )            dfs( i , 0 );    printf("%d\n",maxdeep);}int main(){    while(scanf("%d", &n) , n)    {        init();        solve();    }    return 0;}


HOJ 3008 Matryoshka Dolls, Again

        坑爹啊,上面某道题的加强版啊,然后就变成匹配啦。。。。当时还拿搜索做来着,超时啊。。。。后来用匈牙利算法。。。强大啊。。。
        算是一道难题吧。。。。
#include <iostream>#define N 510using namespace std;int f[ N ], ans, n, tot_edge, visit[ N ], match[ N ];struct data{    int x,y,z;    void input()    {        scanf("%d %d %d",&x,&y,&z);    }    bool operator< (data b)    {        return x<b.x&&y<b.y&&z<b.z;    }}p[N];struct edge_data{    int v;    edge_data*next;}edge[ N * N ], *adj[ N ]; void push_edge(int u,int v){    edge[ tot_edge ].v = v;    edge[ tot_edge ].next = adj[ u ];    adj[ u ] = &edge[ tot_edge++ ];}void input(){    tot_edge = 0;    memset( adj , 0 , sizeof( adj ) );    int i,j;    for ( i = 0 ; i < n ; i++)        p[ i ].input();    for ( i = 0 ; i < n ; i++)        for ( j = 0 ; j < n ; j++)            if (p[ i ] < p[ j ]) push_edge( i, j );}bool dfs( int k ){    edge_data *temp=adj[ k ];    while( temp )    {        if( !visit[ temp->v ])        {            visit[ temp->v ] = 1;            if( match[ temp->v ] == -1 || dfs( match[ temp-> v ] ) )            {                match[ temp->v ] = k;                return true;            }        }        temp = temp->next;    }    return false;}void solve(){    int ans = 0;    memset( match , -1 , sizeof( match ) );    for ( int i = 0 ; i < n ; i++)    {        memset( visit , 0 , sizeof( visit ) );        if ( dfs( i ) ) ans++;    }    printf("%d\n", n - ans );}int main(){    while (scanf("%d",&n),n)    {        input();        solve();    }    return 0;}


原创粉丝点击