Usaco Training Section 3.3 Camelot

唉,我还是太菜了,一道最短路/搜索题搞了这么久,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;
}

猜你喜欢

转载自blog.csdn.net/qq_36911709/article/details/81988233
今日推荐