有两个考试,选了第1个。
题目的意思是W*H的方格,从S点到G点,中间要经过所有的n个checkpoint,求最短路。其中有的点不能走。
如果没有checkpoint的话,一个BFS就可以了。最开始想到贪心,从S开始,每次选择最近的那个点,但很容易找出反例来。
后来想,题目无非就是在S和G中安排n个点,以一定的次序使得依次连起来之后路径长度最短,因此一次添加一个点,假设之前已经安排好k个点,新加的点一共有k+1个位置可选。从这些可选点中选择最优解。但又找到了反例。
于是想到了动态规划,dp[i][j]表示已经选好了前i-1个点,选择j作为下一个添加的点的最优解。
令S为0,1到n位CP点,n+1为G点,于是dp[i][j]=min(dp[i-1][k]+dis[k][j],k从0到n)。需要注意的是要保证前i-1个点中没有j。最多18个CP,可以用一个整形(32位)来保存已经选择的点。还有一个需要注意的是k是从0到n,而不是到n+1,因为前i-1个点中不能有G点。
开始时对每个点BFS求任意两个点之间的最短路。
1 #include<stdlib.h>
2 #include<iostream>
3 #include<stdio.h>
4 #include<string.h>
5 #include<vector>
6 #include<list>
7 #include<queue>
8 #include<sstream>
9 #include<map>
10 #define inf 0x7fffffff
11 #define LL long long
12 #define MAX_E 1000000
13 #define MAX_V 500
14 #define MAX_N 105
15 using namespace std;
16 char mat[MAX_N][MAX_N];
17 int bit[MAX_N][MAX_N];
18 //对应坐标是否有CP
19 int pos[MAX_N][MAX_N];
20 int dis[MAX_N][MAX_N];
21 int dp[MAX_N][MAX_N];
22 int n=0;
23 int W,H;
24 struct Pos{
25 int h,w;
26 int levle;
27 Pos(){
28 h=w=levle=0;
29 }
30 Pos(int _h,int _w,int _levle){
31 h=_h;
32 w=_w;
33 levle=_levle;
34 }
35 };
36 int dh[4]={-1,0,1,0};
37 int dw[4]={0,1,0,-1};
38 void bfs(int h,int w){
39 int s=pos[h][w];
40 dis[s][s]=0;
41 Pos start(h,w,0);
42 queue<Pos> q;
43 q.push(start);
44 bool visited[MAX_N][MAX_N];
45 memset(visited,0,sizeof(visited));
46 visited[h][w]=1;
47 while(!q.empty()){
48 Pos t=q.front();
49 q.pop();
50 for(int i=0;i<4;i++){
51 int hh=t.h+dh[i],ww=t.w+dw[i];
52 //非墙壁
53 if(hh>=0&&hh<H&&ww>=0&&ww<W&&mat[hh][ww]!=‘#‘&&!visited[hh][ww]){
54 Pos add(hh,ww,t.levle+1);
55 q.push(add);
56 visited[hh][ww]=1;
57 int p=pos[hh][ww];
58 if(p>=0&&dis[s][p]==inf){
59 dis[s][p]=add.levle;
60 }
61 }
62 }
63 }
64 }
65 void solve(){
66 //初始化起点,终点和CP点的位置
67 //0为起点,1..n为CP点,n+1为终点
68 n=0;
69 memset(pos,-1,sizeof(pos));
70 for(int i=0;i<H;i++){
71 for(int j=0;j<W;j++){
72 if(mat[i][j]==‘@‘){
73 pos[i][j]=++n;
74 }
75 }
76 }
77 for(int i=0;i<H;i++){
78 for(int j=0;j<W;j++){
79 if(mat[i][j]==‘S‘){
80 pos[i][j]=0;
81 }
82 if(mat[i][j]==‘G‘){
83 pos[i][j]=n+1;
84 }
85 }
86 }
87 //
88 for(int i=0;i<=n+1;i++)
89 {
90 fill(dis[i],dis[i]+n+2,inf);
91 }
92 for(int i=0;i<H;i++)
93 for(int j=0;j<W;j++){
94 if(pos[i][j]>=0)
95 bfs(i,j);
96 }
97 for(int i=0;i<=n+1;i++)
98 fill(dp[i],dp[i]+n+2,inf);
99 memset(bit,0,sizeof(bit));
100 dp[0][0]=0;
101 bit[0][0]=1;
102 for(int i=1;i<=n+1;i++){
103 for(int j=1;j<=n+1;j++){
104 int M=inf,t=-1;
105 //注意,这里不能到n+1,第1到n步不能包含G
106 //若包含,在考虑最后一个点时,若前n个里均已包含G点,则此时求出的值为无穷大
107 for(int k=0;k<=n;k++){
108 if(dp[i-1][k]!=inf&&(bit[i-1][k]&(1<<j))==0)
109 if(M>dp[i-1][k]+dis[k][j]){
110 M=dp[i-1][k]+dis[k][j];
111 t=k;
112 }
113 }
114 if (t!=-1) {
115 dp[i][j]=M;
116 bit[i][j]=bit[i-1][t]|(1<<j);
117 }
118 }
119 }
120 cout<<dp[n+1][n+1]<<endl;
121 }
122 class Orienteering{
123 public:
124 void main();
125 };
126 void Orienteering::main(){
127 while(scanf("%d%d",&W,&H)!=EOF){
128 getchar();
129 for(int i=0;i<H;i++)
130 scanf("%s",mat[i]);
131 solve();
132 }
133 }
134 int main(int argc, char* argv[]) {
135 Orienteering o;
136 o.main();
137 return 0;
138 }
提交之后才发现题目要求图不符合要求和不能到达终点时输出-1,%>_<%没处理
WAP 2014 Examination 1,布布扣,bubuko.com
时间: 2024-11-16 14:34:12