• USACO 2.4


    USACO 2.4.1 

    题解:

    模拟。

    用一个6维数组储存农夫与奶牛当前状态是否出现过,若出现过则表明出现循环,直接输出0,f[农夫x][农夫y][农夫方向][奶牛x][奶牛y][奶牛方向]。

    最后注意转弯要算一步。

    代码:

    /*
    ID:m1599491
    PROB:ttwo
    LANG:C++
    */
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    using namespace std;
    
    string s[12];
    int i,j,xf,xc,yf,yc;
    bool sta[11][11][5][11][11][5]={0};
    const int dx[4]={-1,0,1,0};
    const int dy[4]={0,1,0,-1};
    
    bool obs(int x,int y,int dir)
    {
        dir--;
        if (x+dx[dir]>10 || x+dx[dir]<=0 || y+dy[dir]>=10 || y+dy[dir]<=-1) return 1;
        if (s[x+dx[dir]][y+dy[dir]]=='*') return 1;
        return 0;
    }
    
    main()
    {
        freopen("ttwo.in","r",stdin);
        freopen("ttwo.out","w",stdout);
        for (i=1; i<=10; i++) 
        {
            cin>>s[i];
            for (j=0; j<s[i].size(); j++)
            {
                if (s[i][j]=='F') {xf=i;yf=j;s[i][j]='.';}
                if (s[i][j]=='C') {xc=i;yc=j;s[i][j]='.';}
            }
        }
        int dirf=1,dirc=1,ans=0,hh=0;
        while (1==1)
        {
            if (xf==xc && yf==yc) {printf("%d
    ",ans);break;}
            if (sta[xf][yf][dirf][xc][yc][dirc]) {printf("0
    ");return 0;}
            sta[xf][yf][dirf][xc][yc][dirc]=1;
            int a=dirf,b=dirc;
            if (obs(xf,yf,dirf)) {if (dirf==4) dirf=1; else dirf++;}
            if (a==dirf) {xf+=dx[dirf-1];yf+=dy[dirf-1];}
            if (obs(xc,yc,dirc)) {if (dirc==4) dirc=1; else dirc++;}
            if (b==dirc) {xc+=dx[dirc-1];yc+=dy[dirc-1];}
            ans++;
        }
        return 0;
    }
    The Tamworth Two

    USACO 2.4.2

    题解:

    其实就是一个迷宫,虽然有两个出口,但只需要一遍BFS就够了,将两个出口的坐标同时加入队列就行了,dis[i][j]表示从(i,j)走出迷宫的最短距离。

    最后整个图扫一遍,更新答案。

    代码:

    /*
    ID:m1599491
    PROB:maze1
    LANG:C++
    */
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<algorithm>
    #include<iostream>
    #define MAXN 210
    using namespace std;
    
    const int dx[4]={-1,0,1,0};
    const int dy[4]={0,1,0,-1};
    string s[MAXN];
    int dis[MAXN][MAXN],f[10010][2],g[MAXN][MAXN];
    int i,j,front,tail=1,w,h,fx,fy;
    
    void bfs(int x1,int y1,int x2,int y2)
    {
        int i,j,x,y;
        memset(dis,-1,sizeof(dis));
        dis[x1][y1]=dis[x2][y2]=0;
        f[++front][1]=x1;f[front][2]=y1;
        f[++front][1]=x2;f[front][2]=y2;
        while (tail<=front)
        {
            x=f[tail][1];y=f[tail][2];
            for (i=0; i<=3; i++)
            {
                fx=x+dx[i];fy=y+dy[i];
                if (fx<0 || fx>=h || fy<0 || fy>=w) continue;
                if (s[fx][fy]!=' ') continue;
                if (dis[fx][fy]==-1 || dis[fx][fy]>dis[x][y])
                {
                    f[++front][1]=fx;f[front][2]=fy;
                    if (fx%2==0 || fy%2==0) dis[fx][fy]=dis[x][y];
                    else dis[fx][fy]=dis[x][y]+1;
                }
            }
            tail++;
        }
    }
    
    main()
    {
        freopen("maze1.in","r",stdin);
        freopen("maze1.out","w",stdout);
        scanf("%d%d",&w,&h);getline(cin,s[1]);
        w=w*2+1;h=h*2+1;
        int x1=-1,y1=-1,x2,y2;
        for (i=0; i<=h-1; i++) getline(cin,s[i]);
        for (i=0; i<h; i++) for (j=0; j<w; j++)  
        {
            if (s[i][j]==' ' && (i==0 || j==0 || i==h-1 || j==w-1))
            if (x1==-1) {x1=i;y1=j;} else {x2=i;y2=j;}
        }
        bfs(x1,y1,x2,y2);
        int ans=0;
        for (i=0; i<h; i++) for (j=0; j<w; j++) ans=max(ans,dis[i][j]);
        printf("%d
    ",ans);
        return 0;
    }
    Overfencing

    USACO 2.4.3

    题解:

    这题剧毒,难点就在于题意。

    先给你N个点的坐标,再给你一个邻接矩阵,若(i,j)=1,则i牧区与j牧区有一条通路(无向)。

    若几个牧区能互相到达则成为一个牧场,一个牧场的直径就是这个牧场里面,所有牧区两两之间的最短距离最大值

    现在有若干个牧场,要求你在任意两个牧场里面的任意两个牧区i,j(i!=j)连一条道路,使得合并之后,所有牧场里面,半径的最大值最小,要你求出这条半径的长度。(这就是题意

    由于N只有150,很容易想到的就是Floyd,但无脑Floyd根本卡不过大数据,就像利用Floyd生成原始情况,然后每条没有连接的边枚举过去,重新Floyd计算一下最大直径。经测试,这种想法在第4个测试数据上用时近半秒,然后第5个点你等了2分钟还没有出解。

    接下来想优化,先用并查集将同一个牧场里的点合并,再用勾股定理预处理出所有点两两之间的距离dis[i][j],然后跑Floyd,注意不同牧场的点不能在Floyd里面计算,保证i,j,k三点在同一牧场。

    再接着,处理出数组mxdis[i],表示i牧区与i牧区所在的牧场的各个牧区的最短距离的最大值。将所有mxdis[i]扫一遍,利用并查集便能求出i牧区所在牧场的直径dia[F[i]],并求出最长的直径MAX。

    最后将每对不在同个牧场的牧区枚举一遍,假设i牧区在甲牧场,j牧区在乙牧场,那么合并之后的牧场丙的直径就是max(dia[F[i]],dia[F[j]],mxdis[i]+dis[i][j]+mxdis[j]),F[i]表示i牧区所在的牧场。由于当前的答案为max(新牧区的直径,其他所有牧区的直径),那么直接就是max(MAX,mxdis[i]+dis[i][j]+mxdis[j]),则ans=min(ans,max(MAX,mxdis[i]+dis[i][j]+mxdis[j]))。

    代码:

    /*
    ID:m1599491
    PROB:cowtour
    LANG:C++
    */
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define MX 200
    using namespace std;
    
    string s;
    int i,j,k,n,f[MX][MX],x[MX],y[MX],F[MX];
    double dis[MX][MX],mxdis[MX],dia[MX],MAX=-1,ans=0x7fffffff;
    
    double min(double x,double y) {return x<y?x:y;}
    double max(double x,double y) {return x>y?x:y;}
    
    double Py(int x1,int y1,int x2,int y2) {return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));}
    
    int GF(int x) {if (F[x]!=x) F[x]=GF(F[x]);return F[x];}
    int MG(int i,int j) {i=GF(i);j=GF(j);if (i!=j) F[i]=j;}
    
    main()
    {
        freopen("cowtour.in","r",stdin);
        freopen("cowtour.out","w",stdout);
        scanf("%d",&n);
        for (i=1; i<=n; i++) F[i]=i;
        for (i=1; i<=n; i++) scanf("%d%d",&x[i],&y[i]);getline(cin,s);
        for (i=1; i<=n; i++)
        {
            getline(cin,s);
            for (j=0; j<s.size(); j++) if (s[j]=='1') 
            {
                f[i][j+1]=1;
                MG(i,j+1);
                dis[i][j+1]=Py(x[i],y[i],x[j+1],y[j+1]);
            }
        }
        for (i=1; i<=n; i++) F[i]=GF(i);
        for (i=1; i<=n; i++) for (j=1; j<=n; j++) if (F[i]!=F[j]) dis[i][j]=Py(x[i],y[i],x[j],y[j]);
        for (k=1; k<=n; k++) for (i=1; i<=n; i++) 
        {
            if (F[k]!=F[i]) continue;
            for (j=1; j<=n; j++)
            {
                if (i==j || F[i]!=F[j]) continue;
                if (dis[i][k]!=0 && dis[k][j]!=0) if (dis[i][j]==0 || dis[i][j]>dis[i][k]+dis[k][j]) dis[i][j]=dis[i][k]+dis[k][j];
            }
        }
        for (i=1; i<=n; i++) for (j=1; j<=n; j++) 
        {
            if (F[i]==F[j]) continue;
            else dis[i][j]=Py(x[i],y[i],x[j],y[j]);
        }
        for (i=1; i<=n; i++) for (j=1; j<=n; j++) if (F[i]==F[j]) mxdis[i]=max(mxdis[i],dis[i][j]);
        for (i=1; i<=n; i++) dia[F[i]]=max(dia[F[i]],mxdis[i]),MAX=max(MAX,dia[F[i]]);
        for (i=1; i<=n; i++) for (j=i+1; j<=n; j++) if (F[i]!=F[j])
        {
            double T=mxdis[i]+dis[i][j]+mxdis[j];
            ans=min(ans,max(T,MAX));
        }
        printf("%.6f
    ",ans);
    }
    Cow Tours

    USACO 2.4.4

    题解:

    输入输出感觉有点麻烦,然后就是SBSPFA了。

    代码:

    /*
    ID:m1599491
    PROB:comehome
    LANG:C++
    */
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<string>
    #define INF 0x7fffffff
    using namespace std;
    
    string s;
    char c1,c2;
    int a[100][100],b[100][100],p[100],dis[100],n,m,i,j,front,tail,k,now,t,x,y,c,ans=INF;
    bool v[100];
    
    main()
    {
        freopen("comehome.in","r",stdin);
        freopen("comehome.out","w",stdout);
        scanf("%d",&n);getchar();
        for (i=1; i<=n; i++)
        {
            getline(cin,s);
            c1=s[0];c2=s[2];c=0;
            for (j=4; j<s.size(); j++) c=c*10+(s[j]-48);
            if (c1<91) x=c1-64+26; else if (c1>96) x=c1-96;
            if (c2<91) y=c2-64+26; else if (c2>96) y=c2-96;
            b[x][0]++;b[x][b[x][0]]=y;if (a[x][y]) a[x][y]=min(a[x][y],c); else a[x][y]=c;
            b[y][0]++;b[y][b[y][0]]=x;if (a[y][x]) a[y][x]=min(a[y][x],c); else a[y][x]=c;
        }
        memset(v,0,sizeof(v));
        for (i=1; i<=52; i++) dis[i]=INF;
        dis[52]=0;front=1;tail=1;p[1]=52;v[52]=1;
        while (front<=tail)
        {
            now=p[front];
            for (i=1; i<=b[now][0]; i++) if (dis[b[now][i]]>dis[now]+a[now][b[now][i]])
            {
                dis[b[now][i]]=dis[now]+a[now][b[now][i]];
                if (!v[b[now][i]])
                {
                    p[++tail]=b[now][i];
                    v[b[now][i]]=1;
                }
            }
            front++;v[now]=0;
        }
        for (i=27; i<=51; i++) if (dis[i]<ans)
        {
            ans=dis[i];
            k=i;
        }
        printf("%c %d
    ",k-26+64,ans);
    }
    Bessie Come Home

    USACO 2.3.5

    题解:

    简单模拟一波。

    先直接输出能整除的情况。

    接着就先输出整数部分与小数点,并统计整数部分+小数点的位数,方便输出。

    last[rem]表示rem这个余数最先在哪里出现,如果遇到last[rem]>0那么说明出现循环节,如果rem=0的话就说明除尽了,然后随便搞搞输出就行了。

    代码:

    /*
    ID:m1599491
    PROG:fracdec
    LANG:C++
    */
    #include<cmath>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    
    int i,j,x,y,z,rem,quo,tot,bg,ed,last[100010]={0},N;
    char c[100010];
    bool loop=0;
    
    int gcd(int x,int y) {if (y==0) return x;return gcd(y,x%y);}
    int num(int x)
    {
        int k=0,div=x;
        while (div) {div=div/10;k++;}
        return k;
    }
    
    main()
    {
        freopen("fracdec.in","r",stdin);
        freopen("fracdec.out","w",stdout);
        scanf("%d%d",&x,&y);
        if (x%y==0) {printf("%d.0
    ",x/y);return 0;}
        z=gcd(x,y);x=x/z;y=y/z;
        if (x/y==0) N=2; else N=num(x/y)+1;
        printf("%d.",x/y);
        rem=x%y;
        while (true)
        {
            tot++;
            last[rem]=tot;
            c[tot]=rem*10/y+48;
            rem=rem*10%y;
            if (!rem) break;
            if (last[rem]) {bg=last[rem];ed=tot-1;loop=1;break;}
        }
        for (i=1; i<=tot; i++) 
        {
            if (loop && i==bg) {if (N%76==0) printf("
    ");printf("(");N++;}
            printf("%c",c[i]);
            N++;
            if (N%76==0) printf("
    ");
        }
        if (loop) {if (N%76==0) printf("
    ");printf(")");}printf("
    ");
        return 0;
    }
    Fractions to Decimals
  • 相关阅读:
    读书笔记之:高级Linux编程(ch14)
    读书笔记之:C++编程惯用法——高级程序员常用的方法和技巧
    读书笔记之:sed与awk
    读书笔记之:Linux——命令、编辑器与shell编程
    读书笔记之:C++必知必会
    读书笔记之:Linux程序设计(第4版)(ch17)
    读书笔记之:Linux管理员指南与Linux系统一本通
    读书笔记之:C++语言的设计与演化(2002)
    读书笔记之:Linux一站式学习
    读书笔记之:GNU/Linux编程指南
  • 原文地址:https://www.cnblogs.com/HAdolf-HQY/p/7259273.html
Copyright © 2020-2023  润新知