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];The Tamworth Twoint 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; }
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