孤岛营救问题
【问题描述】
1944 年,特种兵麦克接到国防部的命令,要求立即赶赴太平洋上的一个孤岛,营救被敌军俘虏的大兵瑞恩。
瑞恩被关押在一个迷宫里,迷宫地形复杂,但幸好麦克得到了迷宫的地形图。
迷宫的外形是一个长方形,其南北方向被划分为 N 行,东西方向被划分为 M 列,于是整个迷宫被划分为 N×M 个单元。
每一个单元的位置可用一个有序数对(单元的行号单元的列号)来表示。南北或东西方向相邻的 2 个单元之间可能互通,也可能有一扇锁着的门,或者是一堵不可逾越的墙。
迷宫中有一些单元存放着钥匙,并且所有的门被分成 P 类,打开同一类的门的钥匙相同,不同类门的钥匙不同。
大兵瑞恩被关押在迷宫的东南角,即 (N,M) 单元里,并已经昏迷。
迷宫只有一个入口,在西北角。也就是说,麦克可以直接进入 (1,1) 单元。
另外,麦克从一个单元移动到另一个相邻单元的时间为 1 ,拿取所在单元的钥匙的时间以及用钥匙开门的时间可忽略不计。
【编程任务】
试设计一个算法,帮助麦克以最快的方式到达瑞恩所在单元,营救大兵瑞恩。
【输入描述】
第 1 行有 3 个整数,分别表示 N,M,P 的值。
第 2 行是 1 个整数 K ,表示迷宫中门和墙的总数。
第 I+2 行 (1<=I<=K) ,有 5 个整数,依次为 Xi1,Yi1,Xi2,Yi2,Gi :
当 Gi>=1 时,表示 (Xi1,Yi1) 单元与 (Xi2,Yi2) 单元之间有一扇第 Gi 类的门。
当 Gi=0 时,表示 (Xi1,Yi1) 单元与 (Xi2,Yi2) 单元之间有一堵不可逾越的墙。
其中, |Xi1−Xi2|+|Yi1−Yi2|=1,0<=Gi<=P 。
第 K+3 行是一个整数 S ,表示迷宫中存放的钥匙总数。
第 K+3+J 行 (1<=J<=S) ,有 3 个整数, 依次为 Xi1,Yi1,Qi ,表示第 J 把钥匙存放在 (Xi1,Yi1) 单元里,并且第 J 把钥匙是用来开启第 Qi 类门的(其中 1<=Qi<=P ) 。
输入数据中同一行各相邻整数之间用一个空格分隔。
【输出描述】
输出共一行,即麦克营救到大兵瑞恩的最短时间,如果问题无解,则输出 −1 。
【输入样例】
4 4 9
9
1 2 1 3 2
1 2 2 2 0
2 1 2 2 0
2 1 3 1 0
2 3 3 3 0
2 4 3 4 1
3 2 3 3 0
3 3 4 3 0
4 3 4 4 0
【输出示例】
2
2 1 2
4 2 1
14
【Solution】
这个题目我用的是状压DP。
用 fx,y,z 表示在 (x,y) ,而状态为 z 。
然后就可以愉快地DP了。
【Code】
- #include
- #include
- #include
-
- #define Min(x,y) ((x)<(y)?(x):(y))
- #define PLA(x,y) (((x)-1)*m+(y))
- #define ff1 data[i][1]
- #define ff2 data[i][2]
-
- using namespace std;
-
- int n,m,p,K,S;
- int minx;
- int cnt;
-
- int head[200],nxt[1000],data[1000][3];
- int f[11][11][20000];
- int map[11][11][11][11];
- bool ms[11][11][210];
- int vis[11][11][20000];
-
- void add(int x,int a,int b){
- nxt[cnt]=head[x];data[cnt][1]=a;data[cnt][2]=b;head[x]=cnt++;
- }
-
- int judge(int x,int y,int now){
- for(int i=1;i<=K;i++)
- if(ms[x][y][i])
- now|=(1<<(i-1));
- return now;
- }
-
- void dfs(int x,int y,int now){
-
- int q[5][4];
-
- if(vis[x][y][now]!=-1&&vis[x][y][now]==f[x][y][now])return;
-
- int tmp=judge(x,y,now);
- vis[x][y][now]=f[x][y][now];
-
- int cc=0;
-
- for(int i=head[PLA(x,y)];i!=-1;i=nxt[i]){
- if((!(map[x][y][ff1][ff2])||(tmp&(1<<(map[x][y][ff1][ff2]-1))))&&(f[ff1][ff2][tmp]==-1||(f[ff1][ff2][tmp]!=-1&&f[ff1][ff2][tmp]>f[x][y][now]+1))){
- f[ff1][ff2][tmp]=f[x][y][now]+1;
- q[++cc][1]=ff1;q[cc][2]=ff2;q[cc][3]=tmp;
- }
- }
-
- for(int i=1;i<=cc;i++)dfs(q[i][1],q[i][2],q[i][3]);
-
- }
-
- int main(){
-
- freopen(”rescue.in”,“r”,stdin);
- freopen(”rescue.out”,“w”,stdout);
-
- scanf(”%d%d%d%d”,&n,&m,&p,&K);
- for(int i=1;i<=K;i++){
- int x,y,a,b,c;
- scanf(”%d%d%d%d%d”,&x,&y,&a,&b,&c);
- if(c==0)c=-1;
- map[x][y][a][b]=map[a][b][x][y]=c;
-
- }
-
- scanf(”%d”,&S);
- for(int i=1;i<=S;i++){
- int x,y,z;
- scanf(”%d%d%d”,&x,&y,&z);
- ms[x][y][z]=true;
- ms[x][y][0]=true;
- }
-
- minx=0x3f3f3f3f;
- memset(head,-1,sizeof head);
- memset(f,-1,sizeof f);
- memset(vis,-1,sizeof vis);
-
- for(int i=1;i<=n;i++)
- for(int j=1;j<=m;j++){
- if(i+1<=n&&map[i][j][i+1][j]!=-1)add(PLA(i,j),i+1,j);
- if(j+1<=m&&map[i][j][i][j+1]!=-1)add(PLA(i,j),i,j+1);
- if(i-1>=1&&map[i][j][i-1][j]!=-1)add(PLA(i,j),i-1,j);
- if(j-1>=1&&map[i][j][i][j-1]!=-1)add(PLA(i,j),i,j-1);
- }
-
- f[1][1][0]=0;
- dfs(1,1,0);
-
- for(int i=0;i<=(1<
- if(minx==0x3f3f3f3f)minx=-1;
- printf(”%d\n”,minx);
-
- return 0;
- }