usaco Camelot


 被这道BFS不带权图的最短路水题卡了三天,提交了80次。。。。。。就这样弱成渣了。。。。。。。。
  这道题其实思路很简单,先求出每个点到所有点的最短路,然后枚举集合点,枚举接国王的骑士,枚举接国王的点,算出需要的距离。
    总距离=Min{所有骑士到集合点的距离和-接国王的骑士到集合点的距离+国王到骑士接他的点的距离+骑士到接国王点的距离+其实从接国王的点走到集合点的距离}    (当然太朴素就铁定超时了)
  然后开始处理各个细节。
  首先求最短路,一开始脑子没动当然就想到用Dijkstra求(我有多沙茶。。。),当然O(v*v^2)铁定要超时啊,所以用heap+Dijkstra做了一下。。。果然还是超时。。。这时候我终于缓过神来,这是无权图啊!求无权图的最短路就从每一个点开始走一遍BFS就出来了啊!。。。
  然后是枚举的问题,朴素枚举当然O(n^3)超时,然后观察到这个图最大是30*26,然后估计一下最远的骑士和国王,估算后发现接国王的点应该在国王周围5格内,(这题数据弱,2格内就可以AC了,或者2格是对的?)。然后就胡乱AC了。。。

这是网上一大神的思路




这题对我来说最大的收获就是知道memset(a,0x3f,sizeof(a))a的初值为十位数然而memset(a,10,sizeof(a))a的初值为9位数。

/*
ID:jinbo wu
LANG:C++
TASK:camelot
*/
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
int d[8][2]={{-1,-2},{-2,-1},{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2}};
struct node
{
	int x,y;
}kn[1000];
node king;
int r,c;
int dist[40][30][40][30];
bool vis[40][30];
int kdist[40][30];
int allk[40][30];
queue<pair<int,int> > q;
void bfs(int x,int y)
{
	memset(vis,0,sizeof(vis));
    vis[x][y]=1;
    dist[x][y][x][y]=0;
    q.push(make_pair(x,y));
    while(!q.empty())
    {
    	int kx=q.front().first;
    	int ky=q.front().second;
    	q.pop();
    	for(int i=0;i<8;i++)
    	{
    		int dx=kx+d[i][0];
    		int dy=ky+d[i][1];
    		if(dx>=0&&dx<r&&dy>=0&&dy<c&&!vis[dx][dy])
    		{
    			dist[x][y][dx][dy]=dist[x][y][kx][ky]+1;
    			vis[dx][dy]=1;
    			q.push(make_pair(dx,dy));
    		}
    	}
    }
    return ;

}
int main()
{
  freopen("camelot.in","r",stdin);
  freopen("camelot.out","w",stdout);
  char a;
  int b;
  cin>>r>>c;
  cin>>a>>b;
  king.y=a-'A';
  king.x=b-1;
  int num=0;
  while(cin>>a>>b)
  {
  	kn[num].y=a-'A';
  	kn[num++].x=b-1;
  }
  memset(dist,10,sizeof(dist));
  for(int i=0;i<r;i++)
  	for(int j=0;j<c;j++)
  		bfs(i,j);
  	for(int i=0;i<r;i++)
  		for(int j=0;j<c;j++)
  			kdist[i][j]=max(abs(king.x-i),abs(king.y-j));
  for(int i=0;i<r;i++)
  	for(int j=0;j<c;j++)
  		for(int k=0;k<num;k++)
  			allk[i][j]+=dist[i][j][kn[k].x][kn[k].y];
  		int ans=INF;
  		if(!num)
  		{
  			for(int i=0;i<r;i++)
  				for(int j=0;j<c;j++)
  					ans=min(ans,kdist[i][j]);
  		}
  		else
  		{
  			for(int k=0;k<num;k++)
  			{
  				for(int i=king.x-2;i<king.x+2;i++)
  					for(int j=king.y-2;j<king.y+2;j++)
  						if(i>=0&&i<r&&j>=0&&j<c)
  						{
                              for(int n=0;n<r;n++)
                              	for(int m=0;m<c;m++)
                              		ans=min(ans,abs(allk[n][m]-dist[kn[k].x][kn[k].y][n][m]+dist[kn[k].x][kn[k].y][i][j]+kdist[i][j]+dist[i][j][n][m]));
  						}
  			}
  		}
  		cout<<ans<<endl;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值