【问题描述】
在n个人中,某些人的银行账号之间可以互相转账。这些人之间转账的手续费各不相同。给定这些人之间转账时需要从转账金额里扣除百分之几的手续费,请问A最少需要多少钱使得转账后B收到100元。
请基于教材的图的ADT,选择合适的存储结构,完成该实验项目。
【输入格式】
第一行输入两个正整数n,m,分别表示总人数和可以互相转账的人的对数。
以下m行每行输入三个正整数x,y,z,表示标号为x的人和标号为y的人之间互相转账需要扣除z%的手续费(z<100)。
最后一行输入两个正整数A,B。数据保证A与B之间可以直接或间接地转账。
注意: 2<=N<=20,1<=M<=20,1<=Q<=100
【输出格式】
输出A使得B到账100元最少需要的总费用。精确到小数点后8位。
【输入样例】
3 3
1 2 1
2 3 2
1 3 4
1 3
【输出样例】
103.07153164
注意:其他的代码类似于上一篇文章写的内容,这里不做赘述,只列出改动部分。
链接如下:HNU图的实现(邻接表和邻接矩阵)_Tartaglia_的博客-CSDN博客
改动代码段:
grlist.h
//主要区别在于将glist.h里面边的权值的int型转化为double
class Edge
{
int vert;
double wt;
public:
Edge()
{
vert = -1;
wt = -1;
}
Edge(int v, double w)
{
vert = v;
wt = w;
}
int vertex()
{
return vert;
}
double weight()
{
return wt;
}
};
void setEdge(int i, int j, double weight) //主要改动部分,double
{
// Assert(weight>0, "May not set weight to 0");
assert(weight > 0);
Edge currEdge(j, weight);
if (isEdge(i, j)) // Edge already exists in graph
{
vertex[i]->remove();
vertex[i]->insert(currEdge);
}
else // Keep neighbors sorted by vertex index
{
numEdge++;
for (vertex[i]->moveToStart();
vertex[i]->currPos() < vertex[i]->length();
vertex[i]->next())
{
Edge temp = vertex[i]->getValue();
if (temp.vertex() > j) break;
}
vertex[i]->insert(currEdge);
}
}
double weight(int i, int j) // Return weight of (i, j)
{
Edge curr;
if (isEdge(i, j))
{
curr = vertex[i]->getValue();
return curr.weight();
}
else return 0;
}
Graph_test.h
//主要区别在于建立一个新的Dijkstral_函数,这个函数的基础在于Dijkstral,但是和它并不完全一样
void Dijkstral_(double* D, int s,int ss)
{
for(int i=0;i<G->n();i++)
D[i]=G->weight(s,i); /*定义从出发点s到其他全部点的距离,也就是转化后能够得到的钱数的占比*/
D[s]=1; //出发点到自身的不经过他人,钱数仍然为原来的,定义为1
G->setMark(s,VISITED);
for(int i=0;i<G->n()-2;i++)
{
double mm=0;
int k;
for(int j=0;j<G->n();j++) //找到和出发点s相连的点的具有最大权值的边
{
if(G->getMark(j)==UNVISITED&&D[j]>mm)
{
k=j;
mm=D[j];
}
}
G->setMark(k,VISITED);
if(k==ss) return ;
for(int j=0;j<G->n();j++)
if(G->getMark(j)==UNVISITED&&D[j]<D[k]*G->weight(k,j) )
D[j]=D[k]*G->weight(k,j); /*更新权值,即:将从s点直接到其他点或者间接到达其他点的权值,更改为能够找到最大权值的路*/
}
}
main.h
int main()
{
Graph* G;
int vert_num=0,m=0; // 图的顶点数,编号从0开始
cin >> vert_num>>m;
G = createGraph(1, vert_num);
int front=0, to=0;
double wt=0;
while(m--) //更改权值,改为能够得到钱的百分比
{
double wt1=0;
cin >> front >> to >> wt;
wt1=double((100-wt)/100);
G->setEdge(front-1, to-1, wt1);
G->setEdge(to-1, front-1, wt1);
}
int open=0,end=0;
cin>>open>>end;
option *it = new option(G);
for (int v = 0; v < G->n(); v++)
G->setMark(v, UNVISITED); // 确定每一个点都是没有被访问过的
double D[G->n()];
for (int i = 0; i < G->n(); i++) //初始化
D[i] = INFINITY;
it->Dijkstral_(D, open-1,end-1);
printf("%.8f\n", 100/D[end-1] - 0.000000005); /*方便输出保留8位小数的数字,并且避免C++语言的四舍五入*/
return 0;
}