NOIP2015 Day1

来源:互联网 发布:淘宝小二几点上班 编辑:程序博客网 时间:2024/06/05 08:19

T1 神奇的幻方

喜闻乐见NOIP2017初赛阅读程序第一题

按题意模拟即可
O(n2)

#include<bits/stdc++.h>using namespace std;#define N 50int a[N][N];int main(){    int n,i,j;    scanf("%d",&n);    int x=1,y=n/2+1;    a[x][y]=1;    for (i=2;i<=n*n;i++){        if (x==1 && y!=n) x=n,y++;        else if (x!=1 && y==n) x--,y=1;        else if (x==1 && y==n) x++;        else if (x!=1 && y!=n && !a[x-1][y+1]) x--,y++;        else x++;        a[x][y]=i;    }    for (i=1;i<=n;i++)        for (j=1;j<=n;j++)            printf("%d%c",a[i][j]," \n"[j==n]);    return 0;}

T2 信息传递

显然就是在一个有向图上找一个最小的环
那么直接枚举没遍历的点BFS即可
其实正解是拓扑排序 但是按照这样子写也是对的
因为这样该找到的环依然会找到
具体例子就不举了= =
O(n)

#include<bits/stdc++.h>using namespace std;#define N 200010void rd(int &x){    char c;x=0;    while (c=getchar(),c<48);    do x=(x<<1)+(x<<3)+(c^48);    while (c=getchar(),c>=48);}struct edge{    int nxt,t;}e[N];int head[N],edge_cnt;void add_edge(int x,int y){    e[edge_cnt]=(edge){head[x],y};    head[x]=edge_cnt++;}int n,Q[N],id[N];bool mark[N];int BFS(int x){    int i,l=1,r=1,res=n;    Q[1]=x;    id[x]=1;    while (l<=r){        int x=Q[l++];        for (i=head[x];~i;i=e[i].nxt){            int to=e[i].t;            if (mark[to]) continue;            if (id[to]) res=min(res,id[x]+1-id[to]);            else{                id[to]=id[x]+1;                Q[++r]=to;            }        }    }    for (i=1;i<=r;i++) mark[Q[i]]=1;    return res;}int main(){    memset(head,-1,sizeof(head));    int i;    scanf("%d",&n);    for (i=1;i<=n;i++){        int x; rd(x);        add_edge(i,x);    }    int ans=n;    for (i=1;i<=n;i++)        if (!mark[i]) ans=min(ans,BFS(i));    printf("%d\n",ans);    return 0;}

T3 斗地主

一道很(e)好(xin)的搜索题
而且题意及其不清晰 有很多搭配规则需要选手自行领悟
主要介绍两种我自己想出来的奇怪写法

解法1

只搜索搭配的牌 把1/2/3/4张单独出的最后计算
这样可以减少很多复杂度

#include<bits/stdc++.h>using namespace std;#define N 20int n,a[N],ans;int get(){    int i;    int res=0;    for (i=1;i<=13;i++)        if (a[i]) res++;    return res+(a[14]+a[15]+1)/2;}void dfs(int t,int s,int l){    ans=min(ans,s+get());//单牌直接在这里处理    if (!t) return;    int i,j,k;    if (t>=8 && l<=1){        for (i=1;i<=13;i++)//四带二对            if (a[i]>=4){                a[i]-=4;                for (j=1;j<=13;j++)                     if (i!=j && a[j]>=2){                        a[j]-=2;                        for (k=j;k<=13;k++)                            if (i!=k && a[k]>=2){                                a[k]-=2;                                dfs(t-8,s+1,1);                                a[k]+=2;                            }                        a[j]+=2;                    }                a[i]+=4;            }    }    if (t>=6 && l<=2){        for (i=1;i<=11;i++)//三顺子             if (a[i]>=3 && a[i+1]>=3){                a[i]-=3;                for (j=i+1;a[j]>=3 && j<=12;j++){                    a[j]-=3;                    dfs(t-(j-i+1)*3,s+1,2);                }                for (k=i;k<j;k++) a[k]+=3;             }        for (i=1;i<=10;i++)//双顺子             if (a[i]>=2 && a[i+1]>=2 && a[i+2]>=2){                a[i]-=2; a[i+1]-=2;                for (j=i+2;a[j]>=2 && j<=12;j++){                    a[j]-=2;                    dfs(t-(j-i+1)*2,s+1,2);                }                for (k=i;k<j;k++) a[k]+=2;            }        for (i=1;i<=13;i++)//四带二             if (a[i]>=4){                a[i]-=4;                for (j=1;j<=15;j++)//可以带王                     if (i!=j && a[j]){                        a[j]--;                        for (k=j;k<=15;k++)//可以带两个相同的                             if (i!=k && a[k]){                                a[k]--;                                dfs(t-6,s+1,2);                                a[k]++;                            }                        a[j]++;                    }                a[i]+=4;            }    }    if (t>=5 && l<=3){        for (i=1;i<=8;i++)//单顺子             if (a[i] && a[i+1] && a[i+2] && a[i+3] && a[i+4]){                a[i]--; a[i+1]--; a[i+2]--; a[i+3]--;                for (j=i+4;a[j] && j<=12;j++){                    a[j]--;                    dfs(t-(j-i+1),s+1,3);                }                for (k=i;k<j;k++) a[k]++;            }        for (i=1;i<=13;i++)//三带二             if (a[i]>=3){                a[i]-=3;                for (j=1;j<=13;j++)                    if (i!=j && a[j]>=2){                        a[j]-=2;                        dfs(t-5,s+1,3);                        a[j]+=2;                    }                a[i]+=3;            }    }    if (t>=4 && l<=4){        for (i=1;i<=13;i++)//三带一             if (a[i]>=3){                a[i]-=3;                for (j=1;j<=15;j++)//可以带王                     if (i!=j && a[j]){                        a[j]--;                        dfs(t-4,s+1,4);                        a[j]++;                    }                a[i]+=3;            }    }}int main(){    int Case,i;    scanf("%d%d",&Case,&n);    while (Case--){        memset(a,0,sizeof(a));        for (i=1;i<=n;i++){            int x,y;            scanf("%d%d",&x,&y);            a[x>2?x-2:(x?x+11:13+y)]++;        }        ans=n;        dfs(n,0,1);        printf("%d\n",ans);    }    return 0;}

解法2

搜索全部的种类
按照出的牌数从大到小搜索 防止出现重复
用A*剪枝
由于数据保证随机也可以用一个不准确的估价函数保证时间

#include<bits/stdc++.h>using namespace std;#define N 20int n,a[N],ans;void dfs(int t,int s,int l,int Las){//l用来保证出牌顺序    ans=min(ans,s+t);//单牌直接在这里处理    if (s+(int)ceil(1.0*t/max(Las,t))>=ans) return;//准确 120ms    //if (s+(t+9-l-1)/(9-l)>=ans) return;//不准确 28ms    if (!t) return;    int i,j,k;    if (t>=8 && l<=1){        for (i=1;i<=13;i++)//四带二对            if (a[i]>=4){                a[i]-=4;                for (j=1;j<=13;j++)                     if (i!=j && a[j]>=2){                        a[j]-=2;                        for (k=j;k<=13;k++)                            if (i!=k && a[k]>=2){                                a[k]-=2;                                dfs(t-8,s+1,1,8);                                a[k]+=2;                            }                        a[j]+=2;                    }                a[i]+=4;            }    }    if (t>=6 && l<=2){        for (i=1;i<=11;i++)//三顺子             if (a[i]>=3 && a[i+1]>=3){                a[i]-=3;                for (j=i+1;a[j]>=3 && j<=12;j++){                    a[j]-=3;                    dfs(t-(j-i+1)*3,s+1,2,(j-i+1)*3);                }                for (k=i;k<j;k++) a[k]+=3;             }        for (i=1;i<=10;i++)//双顺子             if (a[i]>=2 && a[i+1]>=2 && a[i+2]>=2){                a[i]-=2; a[i+1]-=2;                for (j=i+2;a[j]>=2 && j<=12;j++){                    a[j]-=2;                    dfs(t-(j-i+1)*2,s+1,2,(j-i+1)*2);                }                for (k=i;k<j;k++) a[k]+=2;            }        for (i=1;i<=13;i++)//四带二             if (a[i]>=4){                a[i]-=4;                for (j=1;j<=15;j++)//可以带王                     if (i!=j && a[j]){                        a[j]--;                        for (k=j;k<=15;k++)//可以带两个相同的                             if (i!=k && a[k]){                                a[k]--;                                dfs(t-6,s+1,2,6);                                a[k]++;                            }                        a[j]++;                    }                a[i]+=4;            }    }    if (t>=5 && l<=3){        for (i=1;i<=8;i++)//单顺子             if (a[i] && a[i+1] && a[i+2] && a[i+3] && a[i+4]){                a[i]--; a[i+1]--; a[i+2]--; a[i+3]--;                for (j=i+4;a[j] && j<=12;j++){                    a[j]--;                    dfs(t-(j-i+1),s+1,3,j-i+1);                }                for (k=i;k<j;k++) a[k]++;            }        for (i=1;i<=13;i++)//三带二             if (a[i]>=3){                a[i]-=3;                for (j=1;j<=13;j++)                    if (i!=j && a[j]>=2){                        a[j]-=2;                        dfs(t-5,s+1,3,5);                        a[j]+=2;                    }                a[i]+=3;            }    }    if (t>=4 && l<=4){        for (i=1;i<=13;i++)//三带一             if (a[i]>=3){                a[i]-=3;                for (j=1;j<=15;j++)//可以带王                     if (i!=j && a[j]){                        a[j]--;                        dfs(t-4,s+1,4,4);                        a[j]++;                    }                a[i]+=3;            }        for (i=1;i<=13;i++)//炸弹             if (a[i]>=4){                a[i]-=4;                dfs(t-4,s+1,4,4);                a[i]+=4;            }    }    if (t>=3 && l<=5){        for (i=1;i<=13;i++)//三张牌             if (a[i]>=3){                a[i]-=3;                dfs(t-3,s+1,5,3);                a[i]+=3;            }    }    if (t>=2 && l<=6){        if (a[14] && a[15]){//火箭             a[14]--; a[15]--;            dfs(t-2,s+1,6,2);            a[14]++; a[15]++;        }        for (i=1;i<=13;i++)//对子             if (a[i]>=2){                a[i]-=2;                dfs(t-2,s+1,6,2);                a[i]+=2;            }    } }int main(){    int Case,i;    scanf("%d%d",&Case,&n);    while (Case--){        memset(a,0,sizeof(a));        for (i=1;i<=n;i++){            int x,y;            scanf("%d%d",&x,&y);            a[x>2?x-2:x?x+11:13+y]++;        }        ans=n;        dfs(n,0,1,n);        printf("%d\n",ans);    }    return 0;}

解法3

搜索顺子的情况 接下来用dp求出最少步数

解法4

搜索+贪心

由于这题特别奇怪 各种鬼畜的写法层出不穷
果然是NOIP 就是喜欢乱搞
这种题就是暴力踩标程 乱写能AC

Date:2017/10/26
By CalvinJin

原创粉丝点击