質問D:インターネット独占禁止法
タイトル説明
インターネットは法律の範囲外ではありませんでした。12月2日以降、インターネットの独占禁止は新たな旅を開始しました。まず、Ant Groupは、中国人民銀行、中国銀行保険規制委員会、中国証券監督管理委員会、および国家外貨管理局から共同でインタビューを受けました。12月14日、Alibaba、China Reading Group、Fengchao Networkの3社は、他の企業を買収し、それに応じて事業者集中の違法な実施を宣言しなかったとして、国家市場規制局から50万元の最高レベルの行政処分を受けました。法律で。
12月30日、州市場規制局は、「ダブルイレブン」期間中の自営事業の不適切な価格行動に対して、JD.com、Tmall、およびVipshopに50万元の行政処分を課すという別の動きをしました。
市場経済では、公正な競争だけが悪いコインを排除することができ、独占の結果は悪いコインが良いコインを追い出すことです。
このため、私の国では、銀行が合理的な範囲内で金融サービス手数料の独立した価格決定力を持つことができます。2つの口座間の送金には手数料の控除が必要であり、送金レートは銀行ごとに異なります。
n種類の銀行口座があり、相互に送金できるm組の口座があることが知られています。口座振替のために差し引く必要のある手数料の比率を教えてください。次に、これらのデータに基づいて、指定された2つの口座間で送金された元の金額を調べ、もう一方の口座は100元を受け取ることができます。
入力
最初の行に2つの正の整数nとmを入力します。これらはそれぞれ、口座の総数と、相互に送金できる口座の対数を表します。(0 <n <= 2000)
次のm行の各行に3つの正の整数x、y、zを入力します。これは、xという番号の口座とyという番号の口座の間の送金で手数料のz%を差し引く必要があることを意味します。 (z <100)。
最後の行に2つの正の整数AとBを入力します。
データは、AとBの間で直接または間接的に送金できることを保証します。
出力
出力Aは、最小合計コスト100元のアカウントにBを作成するための転送です。小数点以下8桁まで正確です。
サンプル入力
3 3
1 2 1
2 3 2
1 3 3
1 3
サンプル出力
103.07153164
この質問に関係する知識ポイントはダイクストラアルゴリズムです。最初に、サンプル入力後にサンプル出力がどのように取得されるかを分析します。
100を前の積(1回の手数料)で割って必要な手数料が得られることは難しくありません。コストxが最も低い場合
でも
、スコアの最大値を見つけます。
この質問のエッジウェイトは0%に初期化されます。これは、2つのアカウントが最初に相互に送金できないことを意味します。x、y、zのセットを読み取った後、xというラベルの付いたアカウントとyというラベルの付いたアカウントの間のエッジは(1-z%)として格納されます。ダイクストラのアルゴリズムのアイデアを使用して、スコアマザーの最大値を見つけます。最後に、100 /分母の最大値で理想的な出力結果を得ることができます。あまりナンセンスではありません、コードに移動してください!
#include <stdio.h>
#include <stdlib.h>
#define MAX 2001//账号个数即顶点数n(0<n<=2000)
int visit[MAX];
//定义一个全局数组visit[]用来标记顶点是否被访问过,1代表该顶点已经访问过,0代表该顶点未被访问过 。
//注:定义在main()函数外面的数组,默认初始化为0。
double dist[MAX];
/*
定义一个全局数组dist[]用来存储起始点start到顶点i之间的最大的(1-手续费率)的乘积,
注意到乘积不是整型,而是浮点型,
而最后输出要求精确到小数点后8位,为了安全,我们不妨定义成double类型。
*/
/*邻接矩阵存储图(顶点表和邻接矩阵)
定义图的结构体
*/
typedef struct{
int vex[MAX];//顶点表记录各个顶点信息,由题意显然顶点标号是从1到n。
double edges[MAX][MAX];
/*邻接矩阵记录各个顶点之间的关系,
本题中顶点与顶点间的边表示两个账号之间的转账的(1-手续费率),因此是double类型。*/
int vertexnum,edgenum; //定义顶点数和边数。
}MGraph,*gra;
/*typedef定义新的数据类型,给这个结构体类型取了一个新的别名MGraph,
MGraph类型即结构体类型,并定义了一个指向该结构体类型的指针,名为gra。
*/
//创建图操作
gra createGraph(int n,int m)//createGraph()函数来创建图,返回值类型是gra类型。
{
gra G=(gra)malloc(sizeof(MGraph));
//定义了一个gra类型的变量G,并用malloc()函数给其分配MGraph类型大小的空间。
G->vertexnum=n;//图的顶点数为n。
G->edgenum=m;//图的边数为m。
int i,j;
for(i=1;i<=G->vertexnum;i++)
G->vex[i]=i; //给图的顶点进行初始化操作,本题中顶点编号为1-n。
/*给图的边进行初始化操作,本题中边的权值一开始初始化为0,
代表一开始任意两个账号间都不能进行转账操作。*/
for(i=1;i<=G->vertexnum;i++)
{
for(j=1;j<=G->vertexnum;j++)
G->edges[i][j]=G->edges[j][i]=0;//无向图
}
return G; //返回值类型是gra类型。
}
//求起始点start到目标点target(1-手续费率)乘积的最大值。
void dijkstra(gra G,int start,int target)
{
int i,j;
for(i=1;i<=G->vertexnum;i++)
dist[i]=G->edges[start][i];
/* 一开始把起始点start到顶点i的(1-手续费率)乘积的最大值
初始化为起始点start到顶点i的边的权值*/
//求除起始点外的其他n-1个顶点到起始点(1-手续费率)乘积的最大值(Dijkstra算法思想)
for(i=1;i<G->vertexnum;i++)
{
double max=0;
int pos;
for(j=1;j<=G->vertexnum;j++)
{
if((visit[j]==0)&&(dist[j]>max))
{
max=dist[j];
pos=j;
}
}
visit[pos]=1;
if(pos==target)
break; //找到了起始点到目标点的(1-手续费率)乘积的最大值直接 break。
for(j=1;j<=G->vertexnum;j++)
{
if((visit[j]==0)&&(dist[j]<dist[pos]*G->edges[pos][j]))
dist[j]=dist[pos]*G->edges[pos][j];
}
}
}
int main(int argc, char *argv[]) {
int n,m,x,y,z,i,A,B;
scanf("%d%d",&n,&m);//输入总账号数n和可以互相转账的账号对数m。
gra G=createGraph(n,m);//创建图。
for(i=1;i<=G->edgenum;i++)
{
scanf("%d%d%d",&x,&y,&z);
//输入三个正整数x,y,z,表示标号为x的账号和标号为y的账号之间互相转账需要扣除z%的手续费。
G->edges[x][y]=G->edges[y][x]=(double)(100-z)/100;//无向图。
//边存储的权值为(1-手续费率),是double类型。
}
scanf("%d%d",&A,&B);//输入A,B。
dijkstra(G,A,B);//求得A到B的最大(1-手续费率)的乘积。
printf("%.8lf",100/dist[B]);
/*100/(1-手续费率)的乘积的最大值即为费用的最小值,
同时要求精确到小数点后八位。*/
return 0;
}
この質問は、ダイクストラのアルゴリズムのコードではなく、ダイクストラのアルゴリズムの概念を検証するため、機械的に使用するのではなく、柔軟に使用する必要があります。
難易度は中程度です。
この共有は最初にここで停止します。理解できない場合は、コメント領域にメッセージを残してください。ご参加ありがとうございました!