2011 Spring Trainning Contest SLPC

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

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

HOJ 2999 AAAAHH!Overbooked!

    大水题第一:给了n条线段(开区间),求有木有两条线段有重叠部分。
    排序,然后检查即可。
#include <iostream>
#define N 110
using 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 100
using 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 100100
using 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 1100
using 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 N
using 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 510
using 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;
}


你可能感兴趣的:(2011 Spring Trainning Contest SLPC)