TYVJ1288 飘飘乎居士取能量块

描述

  9月21日,今天是pink的生日,飘飘乎居士当然要去别人的领土大闹一番啦!
  为了收集更多的能量到pink家大闹,飘飘乎居士准备从后花园中取出自己多年积攒的p个能量块。后花园一共被划分n个地区,能量块被分散在里面,现在飘飘乎居士拿出地图,发现自己站在1的地方,而他要做的就是用最短的路程把所有的能量块取出,并且最后走到位于n的出口处,而飘飘乎居士一直是个懒人,他想知道最少要走多少路程才能够取到所有的能量块,并且走到出口

输入格式

第一行一个正整数n,表示花园被划分成了n个地区
接下来一个n*n的矩阵,代表个点之间的相互距离,数据保证从i走到i没有路程
在下来一个整数p,表示一共有p个能量块
接下来一行,表示各个能量块的位置,数据保证1和n没有能量块,且每个地区最多一个能量块
对于所有的数据 0<n<=100  0<=P<=10 任意两点的距离为一个小于1000的正整数

输出格式

一个数,飘飘乎居士所要行走的最小距离


//搜索 全排列       ↑题名字真诡异 

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int n,p;
int a[200][200];//邻接表 
int pos[50];//能量块位置 
int minda=9999999;//存储最优解 
int sum=0;


int main(){
//
scanf("%d",&n);
int i,j;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++){
scanf("%d",&a[i][j]);//读入 
}
scanf("%d",&p);
for(i=1;i<=p;i++)scanf("%d",&pos[i]);//读入能量块位置 
//floyd算法求最短距离 
int k;
for(k=1;k<=n;k++)
 for(i=1;i<=n;i++)
   for(j=1;j<=n;j++)
      if(a[i][j]>a[i][k]+a[k][j])
       a[i][j]=a[i][k]+a[k][j];
//以上 
pos[0]=1;
sort(pos+1,pos+p+1);//从小到大排序能量块位置,很神奇,加了这句话就AC 
//后面函数可能不生效(p不够大时),所以先算一遍 
sum=0;
for(i=1;i<=p;i++){
sum+=a[pos[i-1]][pos[i]];
//
// printf("%d + %d \n c:%d \n",pos[i-1],pos[i],a[pos[i-1]][pos[i]]);
//测试输出用 
}
sum+=a[pos[p]][n];
if(minda>sum)minda=sum;
//
while(next_permutation(pos+1,pos+p+1)){//神奇的函数,作用是求数组全排列 
sum=0;
for(i=1;i<=p;i++){
sum+=a[pos[i-1]][pos[i]];
// printf("%d \n",pos[i]);
}
sum+=a[pos[p]][n];
if(minda>sum)minda=sum;
}
cout<<minda;
return 0;

}


//完毕

总之就是要最短路径遍历1区,n区,每个能量块所在的区

这个next_permutation函数简直好用,省了一番功夫

不用的话,还得自己写一个dfs求全排列


原本的思路是把所有能量块位置+1点+n点一起构成一个新的图,之后发现并不需要,直接在原有a图里做即可

↑另外构建新图可能会导致一些不必要的数据错位


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值