USACO 2.4

Posted HAdolf

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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\n",ans);break;}
        if (sta[xf][yf][dirf][xc][yc][dirc]) {printf("0\n");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\n",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[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\n",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\n",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\n",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("\n");printf("(");N++;}
        printf("%c",c[i]);
        N++;
        if (N%76==0) printf("\n");
    }
    if (loop) {if (N%76==0) printf("\n");printf(")");}printf("\n");
    return 0;
}
Fractions to Decimals

以上是关于USACO 2.4的主要内容,如果未能解决你的问题,请参考以下文章

USACO 2.4Cow Tours (最短路)

连接MySQL出现错误:ERROR 1045 (28000): Access denied for user ‘root‘@‘localhost‘ (using password: YES)(代码片段

$P1215 [USACO1.4]母亲的牛奶 Mother's Milk$

编译原理-第二章 一个简单的语法指导编译器-2.4 语法制导翻译

P3102 [USACO14FEB]秘密代码Secret Code

为啥我需要在 C++ 中使用不同的排序格式来对这个 USACO 代码上的数组和优先级队列进行排序?