题目原址:http://acm.hdu.edu.cn/showproblem.php?pid=2066

大神必须飘过,我在这个题目里面学到了太多太多了。我提交了十六次,错了十二次,反复了这么久才解决内部的悬念。其实这个题目难度真心不大,但是却可以用很多种方式解决;

我知道的当然是用DIJKSTRA算法去解决;然后我把它改成各种形式去做这道题,一开始全错,就是找不到原因,后来才发现是一个数组开小了,因为它可以输入一千个数据,而她想要去的城市也可以输入一千个,相乘后上百万,我只开了一千的数组,这居然成为了一个主要错误原因。后来我干脆不用数组了,直接用一个变量操作;

 解决方法一:
1 #include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=;
const int oo=;
int maze[N][N],Mini[N];
int used[N];
int Upper;
void Dijkstra(int u)
{
memset(used,,sizeof(used));
memset(Mini,,sizeof(Mini));
int i,j,k;
for(i=;i<=Upper;i++)
Mini[i]=maze[u][i];
Mini[u]=;
used[u]=;
for(i=;i<Upper;i++)
{
int mini=oo;
for(j=;j<=Upper;j++)
{
if(!used[j]&&Mini[j]<mini)
{
mini=Mini[j];
k=j;
}
}
used[k]=;
for(j=;j<=Upper;j++)
{
if(!used[j]&&Mini[j]>Mini[k]+maze[k][j])
Mini[j]=Mini[k]+maze[k][j];
}
}
}
int main()
{
int road,near,will;
int Near[N],Will[N];
while(scanf("%d %d %d",&road,&near,&will)==)
{
for(int i=;i<N;i++)
{
for(int j=;j<N;j++)
maze[i][j]=oo;
}
Upper=;
int start,end,value;
for(int i=;i<=road;i++)
{
scanf("%d %d %d",&start,&end,&value);
int temp=(start>end)?start:end;
Upper=(Upper>temp)?Upper:temp;
if(value<maze[start][end])
{
maze[start][end]=value;
maze[end][start]=value;
}
}
int minnumber=oo;//原来我用的不是它,而是一个数组,那更麻烦,也容易犯错,还是这样比较简洁,且没有数组开小的风险
for(int i=;i<=near;i++)scanf("%d",&Near[i]);
for(int i=;i<=will;i++)scanf("%d",&Will[i]);
for(int i=;i<=near;i++)
{
Dijkstra(Near[i]);
for(int j=;j<=will;j++)
if(Mini[Will[j]]<minnumber)
minnumber=Mini[Will[j]];
}
printf("%d\n",minnumber);
}
return ;
}

在不断的犯错过程中,我便尝试了很多其他的办法,也让我非常欣喜的发现了下面的解决办法更加诱人,只是不如上面的容易理解;

因为他要求找出多个起点和结束点之间最短距离的最小值;其实可以把所有的起点都置为零,看作一个起点,从这个总的起点到所有其他点的最短距离就可以方便的求出来了;

所谓把所有的起点都置为零看作一个起点,是说把所有起点之间的距离看为零,这样从一个起点到另外一个起点是不需要任何距离的,然后找到一个起点到终点的最短路径,然后再判断其他起点到终点的最短路径;总之每个点记录的都是起点能到自己的最短距离;

这样值判断终点记录的值的大小就可以了;

input:

7 2 1
2 3 60
2 4 10
2 1 100
1 5 10
4 5 50
3 4 60
2 4 10
2 3
5

output
60

input:
8 2 1
2 3 60
2 4 10
2 1 100
1 5 10
4 5 50
3 4 60
2 4 10
1 3 30
2 3
5

output:

40

如上面图所示:

假如将编号为2 和 3 的点看作两个起始点,5 做为唯一终止点;

将编号2 3 存入数组begin[N]中;并设置2,3的low为零;

有代码for(int i=1;i<=upper;i++)//upper 代表输入的所有数据中的最大数,作为上届

Low[i]=oo;//初始化为无穷大,到达所有点的距离为无穷大

执行完上述步骤后,结果是:low[1]=low[2]=low[3]=low[4]=low[5]=无穷大(oo);

For(int i=1;i<=m;i++)m代表有m个临近城市

Low[begin[i]]=0;//将开始点的low设置为零,代表到达这两点的距离为零

此时结果是:low[2]=low[3]=0,其他的没变

Map[N][N]初始化:map[N][N]=oo;

用map[N][N]数组存储上图;//map数组中所有值初始化为无穷大

Map[1][2]=map[2][1]=100;

Map[2][3]=map[3][2]=60;

Map[1][5]=map[5][1]=10;

········

上述操作完成后,开始遍历操作

有代码:

For(int i=1;i<upper;i++)//要处理upper-1个点,因为最后一个点没有其他未处理的点和它比较了

{

Int Min=oo;int k=0;

For(int j=1;j<=upper;j++)

If(!vis[j]&&low[j]<Min)//vis[N]数组用来标记每一个点是否被处理;vis[i]=0;代表未访问

{ Min=low[j];

k=j;//标记最小元素的下标

}

Vis[k]=1;标记k元素的数为已访问过的

For(int j=1;j<=upper;j++)

If(!vis[j]&&low[j]>low[k]+map[j][k])

Low[j]=low[k]+map[j][k];

第一步遍历会搜索到k=2,因为一开始low[N]里面有两个零和三个无穷大,且k=2在3前面;

标记vis[2]=1;

从1开始搜索和未访问过的点:

1,未访问过,low[1]=oo>(low[k=2]=0)+(map[1][2]=100)=>更新Low[1]=100;

2,已访问;

3,未访问,low[3]=0<任何距离,不会更新

(由此可知,任何两个起点之间的距离都会一直为零,即起点的值不会更新)

4,未访问;low[4]=oo>(low[k=2]=0)+map[2][4]=10)?=true;所以low[4]更新为10;

5,未访问过;(low[5]=oo>(low[k=2]=0)+(map[2][5]=oo))=false=>low[5]不更新;

第一次完毕;

第二次搜索:搜到k=3;

标记vis[3]=1;

1,未访问;low[1]=100>(low[3]=0+map[1][3]=30)=true;=>更新low[1]=30;

2,,3已访问;

4,未访问;Low[4]=10>(low[3]=0+map[3][4]=60)=false;=>low[4]不更新

5,未访问;low[5]=oo>(low[3]=0+map[3][5]=oo)=false;=>low[5]不更新

第二次完毕;

经过上面两次搜索,得到下面结果:

Low[1]=30;low[2]=low[3]=0;low[4]=10;low[5]=oo;

第三次搜索到low[4]=10,k=4;

标记vis[4]=1;

1,未访问;low[1]=30>(low[4]=10+map[4][1]=oo)=false;=>不更新Low[1];

2,3,4已访问;

5,未访问;low[5]=oo>(low[4]=10+map[4][5]=50)=true;=>更新low[5]=60;

第三次搜索完毕;

此时结果是low[1]=30;low[2]=low[3]=0;low[4]=10;low[5]=60;

第四次搜到low[1]=30;k=1;

标记vis[1]=1;

1,2,3,4都已访问过;

5,未访问;low[5]=60>(low[1]=30+map[5][1]=10)=true;=>low[5]更新为40;

所有搜索完毕,此时得到正确答案;

Low[1]=30;low[2]=low[3]=0;low[4]=10;low[5]=40;

详细代码如下:

 #include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int oo=;
const int N=;
int map[N][N];
int upper;
int begin[N];
int low[N];
int near,will;
int vis[N];
void dijkstra()
{
memset(vis,,sizeof(vis));
memset(low,,sizeof(low));
for(int i=;i<=upper;i++)
{
low[i]=oo;
}
for(int i=;i<=near;i++)
{
low[begin[i]]=;
//vis[begin[i]]=1;必须去掉这句
}
int k;
for(int i=;i<upper;i++)
{
int Min=oo;
for(int j=;j<=upper;j++)
{
if(!vis[j]&&low[j]<Min)
{
Min=low[j];
k=j;
}
}
vis[k]=;
for(int j=;j<=upper;j++)
{
if(!vis[j]&&low[j]>low[k]+map[j][k])
low[j]=low[k]+map[j][k];
}
}
}
int main()
{
int n;
while(cin>>n>>near>>will)
{
for(int i=;i<N;i++)
for(int j=;j<N;j++)
map[i][j]=oo;
int start,end,value;
upper=;
for(int i=;i<=n;i++)
{
scanf("%d %d %d",&start,&end,&value);
int temp=start>end?start:end;
upper=upper>temp?upper:temp;
if(map[start][end]>value)
map[start][end]=map[end][start]=value;
}
int mininum=oo;
int te;
for(int i=;i<=near;i++)scanf("%d",&begin[i]);
dijkstra();
for(int i=;i<=will;i++)
{
scanf("%d",&te);
if(low[te]<mininum)mininum=low[te];
}
printf("%d\n",mininum);
}
return ;
}

ACM2066的更多相关文章

随机推荐

  1. 关于C#中如何使用wmi获得操作系统信息?

    最近项目中用到了windows server 2012操作系统中的存储池和ISCSI Disk的技术.前期,我们整个操作都是用power shell脚本去实现了.带来了不方便,后期要使用wmi API ...

  2. CryptoZombies学习笔记——Lesson1

    CryptoZombies是一个学习以太坊开发的平台,我将在这里记录学习过程中的一些笔记. 课程网址:cryptozombies.io 首先是第一课——Lesson1:Making the Zombi ...

  3. metamask注记词

    leaf orbit poet zebra toy day put dinosaur review cool pluck throw(m) 一个钱包地址 里面有多个账号 菲苾代表了不同网络

  4. ServiceStack.Ormlit 事务

    应该使用这个方法开启事务 public static IDbTransaction OpenTransaction(this IDbConnection dbConn) { return new Or ...

  5. 基于angular+bower+glup的webapp

    一:bower介绍 1:全局安装安装bower cnpm i -g bower bower常用指令: bower init //初始化文件 bower install bower uninstall ...

  6. CP文件覆盖问题

    # \cp -r -a aaa/* /bbb[这次是完美的,没有提示按Y.传递了目录属性.没有略过目录]

  7. 嵌入式码农的10年Bug调试经验,值得一看

    下面这些都是我经历过的会导致难点bug的问题: 1.事件顺序.在处理事件时,提出下列问题会很有成效:事件可以以不同的顺序到达吗?如果我们没有接收到此事件会怎么样?如果此事件接连发生两次会怎么样?哪怕通 ...

  8. Java微笔记(3)

    Java 中的 static 使用之静态变量 Java 中被 static 修饰的成员称为静态成员或类成员. 它属于整个类所有,而不是某个对象所有,即被类的所有对象所共享. 静态成员可以使用类名直接访 ...

  9. spring框架(2)— 面相切面编程AOP

    spring框架(2)— 面相切面编程AOP AOP(Aspect Oriented Programming),即面向切面编程. 可以说是OOP(Object Oriented Programming ...

  10. ASP.NET MVC 多语言解决方案

    1:打开VS,新建ASP.NET MVC4项目 2:创建一个放本地化资源的文件夹并命名为"Language",右键选择添加新项,选择资源文件并命名为"Com" ...