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

来源:互联网 发布:网络分销合作协议书 编辑:程序博客网 时间:2024/05/17 20:52

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

个人手速思维训练失败。

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

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

正确理解样例。

想思路,确定完整思路。

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

编码。

测试特殊数据,一般难想,先别急着交,多测试几组比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个数的奇偶就行。


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


阅读全文
0 0
原创粉丝点击