Usaco Training Section 3.3 Camelot
阿新 • • 發佈:2018-11-12
唉,我還是太菜了,一道最短路/搜尋題搞了這麼久,9次才過。
騎士能像馬一樣跳,國王能上下左右對角線走,還可以選一個騎士綁架國王(拖著國王走),問多少步所有人才能聚在一起。
一開始想到了(n*m)^4的做法,就是先從每個點跑個dij,再列舉綁架位置、綁架者、聚集地點、每個騎士。肯定超時。後來發現可以優化。我們在國王只能在一個很小的範圍(+-2)活動,否則答案不是最優的。
貼上有點繁的程式碼(已經刪減過一遍了)
#include<bits/stdc++.h> #define ll long long #define ull unsigned long long #define inf 2147483647 #define mp make_pair #define pii pair<int,int> #define pb push_back using namespace std; struct edg{ int nxt,to; }e[785<<3]; int cnt,head[785]; inline void add(int u,int v){ e[++cnt].nxt=head[u],head[u]=cnt,e[cnt].to=v; } int v[8][2]={-2,1, -1,2, 1,2, 2,1, 2,-1, 1,-2, -1,-2, -2,-1}; int n,m,d[785][785],ax,ay; queue<pii> q; bool vis[785]; vector<int> bx,by,num; inline void dij(int sx,int sy){ int st=(sx-1)*m+sy; for(int i=1;i<=n*m;++i) d[st][i]=inf; d[st][st]=0;q.push(mp(d[st][st],st)); memset(vis,0,sizeof(vis)); while(!q.empty()){ pii t=q.front();q.pop(); int u=t.second,x=t.first; if(vis[u]) continue; for(int i=head[u];i;i=e[i].nxt){ int v=e[i].to; if((ll)x+1<(ll)d[st][v]){ d[st][v]=x+1; q.push(mp(d[st][v],v)); } } vis[u]=1; } } int main() { ios::sync_with_stdio(false); freopen("camelot.in","r",stdin); freopen("camelot.out","w",stdout); cin>>n>>m; char c; cin>>c>>ax; ay=c-'A'+1; int xx,tot=0; while(cin>>c>>xx) bx.pb(xx),by.pb(c-'A'+1),num.pb((xx-1)*m+c-'A'+1),++tot; if(tot==0){ cout<<"0"<<endl; return 0; } int ans=inf; for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) for(int k=0;k<8;++k){ int x=i+v[k][0],y=j+v[k][1]; if(x>0&&x<=n&&y>0&&y<=m) add((i-1)*m+j,(x-1)*m+y); } for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) dij(i,j); for(int i=1;i<=n*m;++i){ int s=0; bool f=1; for(int j=0;j<tot;++j){ if(d[num[j]][i]>=inf){f=0;break;} s+=d[num[j]][i]; } if(!f) continue; int add=inf; for(int ii=2;ii>=-2;--ii) for(int jj=2;jj>=-2;--jj){ int minv=inf,kx=ax+ii,ky=ay+jj; if(kx<=0||kx>n||ky<=0||ky>m) continue; int kp=(kx-1)*m+ky; for(int j=0;j<tot;++j){ int y=inf; if(d[num[j]][kp]<inf&&d[kp][i]<inf) y=d[num[j]][kp]+d[kp][i]-d[num[j]][i]+max(abs(ii),abs(jj)); minv=min(minv,y); } add=min(add,minv); } s+=add; ans=min(ans,s); } cout<<ans<<'\n'; return 0; }