procedure2012
It's not worth it to know you're not worth it!

[关键字]:图论 搜索(有个BFS,有剪枝的思想)

[题目大意]:有一个国王和若干个骑士,国王可以在某一个遇到骑士的点和骑士一起走,要求自己找一个集合点使所有人(骑士+国王)走到这个点的距离最小。

//====================================================================================================

[分析]:usaco的官方题解没看懂……自己也没做出来……我一开始的想法是先处理出每个点到所有骑士的距离和e[u],然后枚举起点u,枚举骑士接国王的点v,枚举哪个骑士接国王k,然后ans=min(e[u]-map[u][k]+map[u][v]+map[u][k]+dis(v)),map[u][v]指从u到v的最短距离BFS可以预处理,dis(v)指国王走到v的步数可以算,总复杂度O(n3)。然后我实在不会优化了,看完题解才知道有两个优化加了可以过,一是如果当前e[u]已经大于ans剪掉,而是接国王的地方不会超过国王坐标+-2的范围(主要剪枝),证明不会……

[代码]:

View Code
/*
ID:procedure2
PROB:camelot
LANG:C++
*/
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;

const int dx[8]={-1,-2,-2,-1,1,2,2,1};
const int dy[8]={-2,-1,1,2,2,1,-1,-2};

struct node
{
int x,y,d;
}q[10000],king,knight[800];
int n,m,tot;
int map[800][800],e[800];
char ch;
bool b[800][800];

void BFS(int sx,int sy)
{
int h=1,t=1;
q[1].x=sx,q[1].y=sy,q[1].d=0;
memset(b,0,sizeof(b));
b[sx][sy]=1;
while (h<=t)
{
for (int i=0;i<8;i++)
{
int xx=q[h].x+dx[i],yy=q[h].y+dy[i];
if (1<=xx && xx<=n && 1<=yy && yy<=m && !b[xx][yy])
{
q[++t].x=xx;
q[t].y=yy;
q[t].d=q[h].d+1;
b[xx][yy]=1;
map[(sx-1)*m+sy][(xx-1)*m+yy]=q[t].d;
}
}
h++;
}
}

int dis(int x,int y)
{
return min(abs(king.x-x),abs(king.y-y))+abs(abs(king.x-x)-abs(king.y-y));
}

int main()
{
freopen("camelot.in","r",stdin);
freopen("camelot.out","w",stdout);
scanf("%d%d\n",&n,&m);
scanf("%c %d\n",&ch,&king.x);
king.x=n-king.x+1,king.y=ch-'A'+1;
while (scanf("%c %d\n",&ch,&knight[++tot].x)!=EOF)
knight[tot].x=n-knight[tot].x+1,knight[tot].y=ch-'A'+1;
tot--;
memset(map,10,sizeof(map));
for (int i=1;i<=n*m;i++) map[i][i]=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
BFS(i,j);
memset(e,0,sizeof(e));
for (int sx=1;sx<=n;sx++)
for (int sy=1;sy<=m;sy++)
{
int u=(sx-1)*m+sy;
for (int i=1;i<=tot;i++)
e[u]+=map[u][(knight[i].x-1)*m+knight[i].y];
}
int ans=0x7fffffff;
for (int sx=1;sx<=n;sx++)
for (int sy=1;sy<=m;sy++)
if (ans>e[(sx-1)*m+sy])
for (int i=max(1,king.x-2);i<=min(n,king.x+2);i++)
for (int j=max(1,king.y-2);j<=min(m,king.y+2);j++)
{
int u=(sx-1)*m+sy,v=(i-1)*m+j;
for (int k=1;k<=tot;k++)
{
int t=(knight[k].x-1)*m+knight[k].y;
int temp=e[u]-map[u][t]+map[u][v]+map[v][t]+dis(i,j);
ans=min(ans,temp);
}
}
if (tot==0) ans=0;
printf("%d\n",ans);
return 0;
}



posted on 2012-02-26 20:17  procedure2012  阅读(387)  评论(0编辑  收藏  举报