1. 程式人生 > >USACO 2.4

USACO 2.4

open sin ++ tar 半徑 over tours front aps

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