第四届福建省大学生程序设计竞赛 部分题解

第四届福建省大学生程序设计竞赛 

个人手速思维训练失败。

还是面临卡题问题,不会冷静下来想哪里有问题,却一直在代码上修改。

读题确定正确题意是首要。

正确理解样例。

想思路,确定完整思路。

计算时间和空间复杂度,想优化。

编码。

测试特殊数据,一般难想,先别急着交,多测试几组比20分钟罚时要好。

观察返回结果(一般是没过):检查代码,数组,数据范围,细节处理。

检查思路。

本场失败原因:A题题意理解错误,反复提交多次提交测试心存侥幸心理,浪费时间。

B题随便交了一发。

CFEFJ没看。

K题思路有问题,忘了处理只有一个联通块两个人同时点火的而不是一个人点火,没有出样例测试,反复修改写法。


Forever 0.5

 构造题,没确定题意,想到了点可以重合也不敢猜,而是一直在试精度。

构造n个点满足:任意两个点距离不超过1,与原点距离不超过1,n对点的距离等于1,这里一对只算一次,理解错误,也没有枚举题意。n个点构成的凸壳面积不小于0.5不大于0.75。

边长为1的正三角形很容易想到,但是不满足面积关系,所以至少需要四个点,在这个基础上加点最合适了,一个正三角形正好有三对点,而加入的一个点与其中一个点距离为1且满足面积关系即可。其实以一个点为圆心,半径为1,另外两个点之间的圆弧上中点就是要求的点,面积正好0.5,且最大。可以有重点,所以n>4的时候都放在那个位置即可。计算可以用特殊数据构造满足条件即可。

 scanf("%d",&n);
        if(n<=3) puts("No");
        else
        {
            puts("Yes");
            printf("%.6f %.6f\n",0.5,0.0);
            printf("%.6f %.6f\n",-0.5,0.0);
            printf("%.6f %.6f\n",0.0,-0.866025);
            printf("%.6f %.6f\n",0.0,0.133975);
            for(int i=5;i<=n;i++) printf("%.6f %.6f\n",0.0,0.133975);
        }


Sub-Bipartite Graph

 

 用的种类并查集的思想去试了一发。赛后补题发现:假设存在已有的两个集合,那么对于新加入的点,和哪个集合的边更多就加入另外一个集合。这样贪心能保证留下的边最多,且大于等于m/2,因为每个点都贡献了与自身相连一半以上的边,注意m的范围,用二维数组计数。

int w[N][N];
int a[N],b[N];
int main()
{
    int t,n,m;
    scanf("%d",&t);
    while(t--)
    {
        cls(w,0);
        scanf("%d%d",&n,&m);
        int u,v;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&u,&v);
            w[u][v]++;
            w[v][u]++;
        }
        int cnt1=0,cnt2=0;
        a[cnt1++]=1;
        for(int i=2;i<=n;i++)
        {
            int num1=0,num2=0;
            for(int j=0;j<cnt1;j++) num1+=w[i][a[j]];
            for(int j=0;j<cnt2;j++) num2+=w[i][b[j]];
            if(num1>=num2) b[cnt2++]=i;
            else a[cnt1++]=i;
        }
        printf("%d",cnt1);
        for(int i=0;i<cnt1;i++) printf(" %d",a[i]);
        puts("");
        printf("%d",cnt2);
        for(int i=0;i<cnt2;i++) printf(" %d",b[i]);
        puts("");
    }
    return 0;
}

C、D以后再补。


Shooting Game

 

补题题意又理解错了,不是,看错题了,没看清题目给出的是单位时间的移动向量。

n只蚊子只要路线会经过空间单位圆就能被消灭,但是没有相关板子,于是就想把经过的时间计算出来,那么最少消灭次数就是区间选点的问题了。

注意FZU输入整数只能用整型接受,用double形会TLE。

int cnt;
struct node
{
    double x,y;
} p[N];
void cal(int id,double x,double y,double z,double x1,double y1,double z1,double r)
{
//    printf("%d: \n",id);
    double a=(x1*1.0)*(x1)+(y1*1.0)*(y1)+(z1*1.0)*(z1);
    double b=2.0*(x*(x1*1.0)+y*1.0*(y1)+z*1.0*(z1));
    double c=1.0*x*x+1.0*y*y+1.0*z*z-r;
    if(a==0)
    {
        if(c<=0)
        {
            p[cnt].x=0;
            p[cnt++].y=INF;
        }
        return ;
    }
    double tmp=b*b-4*a*c;
//    printf("a=%.2f b=%.2f c=%.2f\n",a,b,c);
    if(tmp>=0)
    {
        tmp=sqrt(tmp);
        a*=2.0;
        b=-b;
        double x=(b-tmp)/a;
        double y=(b+tmp)/a;
    //        printf("x=%.6f y=%.6f\n",x,y);
        if(y<0) return ;
        p[cnt].x=x;
        p[cnt++].y=y;
    }
}
int cmp(node a,node b)
{
    if(a.y!=b.y) return a.y<b.y;
    return a.x<b.x;
}
int main()
{
    int t,n;
    ll r;
    scanf("%d",&t);
    int t1=t;
    while(t--)
    {
        cnt=0;
        scanf("%d%I64d",&n,&r);
        int x,y,z,x1,y1,z1;
        r*=r;
        for(int i=1; i<=n; i++)
        {
            scanf("%d%d%d%d%d%d",&x,&y,&z,&x1,&y1,&z1);
            cal(i,x,y,z,x1,y1,z1,r);
        }
        printf("Case %d: %d",t1-t,cnt);
        sort(p,p+cnt,cmp);
        int ans=0;
        if(cnt) ans=1;
        double r=p[0].y;
        for(int i=0; i<cnt; i++)
        {
            if(p[i].x<=r) continue;
            ans++;
            r=p[i].y;
        }
        printf(" %d\n",ans);
    }
    return 0;
}

Easy Game

 

 水题,判串长奇偶。


A-B Game

 水题,大一的时候没做出来。A每次要减少的最多,那么就要A%x最大,那么X就是A的一半加一的时候。

注意数据范围,输入用I64d.


Moon Game

 

水题,很多人居然找各种板子判凸多边形导致问题百出。暴力枚举4个点,判面积关系即可,用叉积的性质:三角形有向面积的2倍,注意取abs

struct point
{
    ll x,y;
} a[50];
ll multi(point p0,point p1,point p2)
{
    return abs((p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y));
}
int main()
{
    int t,n;
    scanf("%d",&t);
    int t1=t;
    while(t--)
    {
        scanf("%d",&n);
        int ans=0;
        for(int i=1; i<=n; i++) scanf("%I64d%I64d",&a[i].x,&a[i].y);
        printf("Case %d: ",t1-t);
        if(n<=3) puts("0");
        else
        {
            for(int i=1; i<=n; i++)
                for(int j=i+1; j<=n; j++)
                    for(int k=j+1; k<=n; k++)
                        for(int l=k+1; l<=n; l++)
                        {
                            ll a1=multi(a[i],a[j],a[k]);
                            ll a2=multi(a[i],a[j],a[l]);
                            ll a3=multi(a[i],a[k],a[l]);
                            ll a4=multi(a[j],a[k],a[l]);
                            if(a4==a1+a2+a3||a3==a1+a2+a4||a2==a1+a3+a4||a1==a2+a3+a4) continue;
                            ans++;
                        }
            pd(ans);
        }
    }
    return 0;
}


K - Fire Game

 2个人各选一个格子点火,求最少需要多少时间烧完所有的汽油格子。

只能各选一次,即联通块个数不超过2,当只有一个连通块的时候是2个人同时点火的,没考虑这里无限WA。。

暴力枚举两个人所选的格子广搜取最大值的最小值即可。

char s[15][15];
int vis[20][20];
int dir[4][2]= {{0,1},{0,-1},{1,0},{-1,0}};
int n,m;
struct node
{
    int x,y,num;
};
void dfs(int x,int y)
{
    s[x][y]='*';
    for(int i=0; i<4; i++)
    {
        int xx=x+dir[i][0],yy=y+dir[i][1];
        if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&s[xx][yy]=='#') dfs(xx,yy);
    }
}
int bfs(int x,int y,int xx,int yy)
{
    int ans=0;
    queue<node>q;
    while(!q.empty()) q.pop();
    memset(vis,0,sizeof(vis));
    vis[x][y]=vis[xx][yy]=1;
    node tmp;
    tmp.x=x,tmp.y=y,tmp.num=0;
    q.push(tmp);
    tmp.x=xx,tmp.y=yy,tmp.num=0;
    q.push(tmp);
    while(!q.empty())
    {
        tmp=q.front();
        q.pop();
        ans=max(ans,tmp.num);
//        if(vis[tmp.x][tmp.y]) continue;
        for(int i=0; i<4; i++)
        {
            int nx=tmp.x+dir[i][0],ny=tmp.y+dir[i][1];
            if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&s[nx][ny]=='*'&&!vis[nx][ny])
            {
                node TC;
                TC.x=nx,TC.y=ny,TC.num=tmp.num+1;
                vis[nx][ny]=1;
                q.push(TC);
            }
        }
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) if(!vis[i][j]&&s[i][j]=='*') ans=INF;
    return ans;
}
int main()
{
    int t;
    scanf("%d",&t);
    int t1=t;
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1; i<=n; i++) scanf("%s",s[i]+1);
        printf("Case %d: ",t1-t);
        int tot=0;
        for(int i=1; i<=n; i++)
            for(int j=1; j<=m&&tot<3; j++)
                if(s[i][j]=='#')
                {
                    tot++;
                    dfs(i,j);
                }
//        for(int i=1;i<=n;i++)
//        {
//            for(int j=1;j<=m;j++)
//                printf("%c",s[i][j]);
//            puts("");
//        }
        if(tot>2) puts("-1");
        else
        {
            int ans=INF;
            for(int i=1; i<=n; i++)
                for(int j=1; j<=m; j++)
                    for(int i1=1; i1<=n; i1++)
                        for(int j1=1; j1<=m; j1++)
                            if(!(i1==i&&j1==j)&&s[i][j]=='*'&&s[i1][j1]=='*')
                            {
                                ans=min(ans,bfs(i,j,i1,j1));
//                                printf("%d %d %d %d %d\n",i,j,i1,j1,bfs(i,j,i1,j1));
                            }
            if(ans==INF) ans=0;
            pd(ans);
        }
    }
    return 0;
}


OOXX Game

 

 水题,每次只能翻转一个O,求O个数的奇偶就行。


手速还是不行,容易敲错,读题能力更多的是理解能力不行容易把问题想偏。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值