1. 程式人生 > >Usaco Training Section 3.3 Camelot

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;
}