USACO Training3.3亚瑟王的宫殿【搜索】By cellur925

题目传送门

因为太蒟了,所以参考了dalao@zbtrs ==    对此表示感谢并侵删。

看起来我们就知道这是搜索题。

最后的情况分两种:有骑士背国王/国王自食其力走到集合点。

首先,我们不知道大家最后集合在哪里,所以可以枚举一下这个点。

其次,我们不知道是哪个骑士背,所以再枚举一下。

再次,我们不知道在哪里接国王,所以再枚举一下这个点。

这是思路的大体框架。然后在更新答案时,我们需要求出在棋盘上一个点到另一点的最短距离。然后因为我们可以等效的认为这是一个无向无环图,所以直接用bfs顺便跑出最短距离就行了==。

细节:赋初值。dis数组和ans都要赋成正无穷。因为我们在寻求一个最小值。

优化:最优性剪枝(代码中)

Code

 1 /*
 2 ID:cellur_2
 3 TASK:camelot
 4 LANG:C++
 5 */
 6 #include<cstdio>
 7 #include<algorithm>
 8 #include<queue>
 9 #include<cstring>
10 
11 using namespace std;
12 const int inf=0x3f3f3f;
13 
14 int n,m,cnt,ans=inf;
15 char ch[5];
16 bool vis[41][27];
17 int dx[10]={0,-2,-1,1,2,2,1,-1,-2};
18 int dy[10]={0,1,2,2,1,-1,-2,-2,-1};
19 int dis[41][27][41][27];
20 int kingx,kingy;
21 struct point{
22     int x,y;
23 }knight[2000];
24 
25 bool valid(int x,int y)
26 {
27     if(x>=1&&x<=n&&y>=1&y<=m) return 1;
28     return 0;
29 }
30 
31 void bfs(int x,int y)
32 {
33     queue<pair<int,int> >q;
34     q.push(make_pair(x,y));
35     memset(vis,0,sizeof(vis));
36     vis[x][y]=1;
37     dis[x][y][x][y]=0;
38     while(!q.empty())
39     {
40         int xx=q.front().first;
41         int yy=q.front().second;
42         q.pop();
43         int step=dis[x][y][xx][yy];
44         for(int i=1;i<=8;i++)
45         {
46             int rx=xx+dx[i];
47             int ry=yy+dy[i];
48             if(valid(rx,ry)&&!vis[rx][ry])
49             {
50                 dis[x][y][rx][ry]=step+1;
51                 q.push(make_pair(rx,ry));
52                 vis[rx][ry]=1;
53             }
54         }
55     }
56 }
57 
58 int main()
59 {
60     freopen("camelot.in","r",stdin);
61     freopen("camelot.out","w",stdout);
62     scanf("%d%d",&n,&m);
63     scanf("%s",ch+1);kingy=(int)ch[1]-'A'+1;
64     scanf("%d",&kingx);kingx=n-kingx+1;
65     while(scanf("%s",ch+1)!=EOF)
66     {
67         knight[++cnt].y=(int)ch[1]-'A'+1;
68         scanf("%d",&knight[cnt].x);
69         knight[cnt].x=n-knight[cnt].x+1;
70     }
71     for(int i=1;i<=n;i++)
72         for(int j=1;j<=m;j++)
73             for(int a=1;a<=n;a++)
74                 for(int b=1;b<=m;b++)
75                     dis[i][j][a][b]=inf;
76     for(int i=1;i<=n;i++)
77         for(int j=1;j<=m;j++)
78             bfs(i,j);
79     for(int i=1;i<=n;i++)
80         for(int j=1;j<=m;j++)
81         {
82             int tmp=0;
83             for(int k=1;k<=cnt;k++)
84                 tmp+=dis[knight[k].x][knight[k].y][i][j];
85             ans=min(ans,tmp+max(abs(kingx-i),abs(kingy-j)));
86             //先考虑国王不被帮助运送的情况 
87             for(int k=1;k<=cnt;k++)
88             {//需要重开变量,不能偷懒用tmp直接减,否则会一直减
89                 int tmpp=tmp-dis[knight[k].x][knight[k].y][i][j];
90                 if(tmp>=ans) continue;//最优性剪枝 
91                 for(int l=1;l<=n;l++)
92                     for(int r=1;r<=m;r++)
93                         ans=min(ans,tmpp+dis[knight[k].x][knight[k].y][l][r]+dis[l][r][i][j]+max(abs(kingx-l),abs(kingy-r)));
94             }
95         }
96     printf("%d\n",ans);
97     return 0;
98 }
View Code

猜你喜欢

转载自www.cnblogs.com/nopartyfoucaodong/p/9636258.html
今日推荐