图论day4(最小花费/刻录光盘)

这篇博客介绍了如何运用图论解决最小花费转账问题和刻录光盘问题。通过bmf算法求解最小费用路径,并讨论了Floyd算法在刻录光盘问题中的应用,强调基础算法知识的重要性以及保持冷静的心态面对挑战。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我迷上bmf简洁的代码了,什么spfa,我不……

luogu1576.最小花费。

在n个人中,某些人的银行账号之间可以互相转账。这些人之间转账的手续费各不相同。给定这些人之间转账时需要从转账金额里扣除百分之几的手续费,请问A最少需要多少钱使得转账后B收到100元。
输入格式:
第一行输入两个正整数n,m,分别表示总人数和可以互相转账的人的对数。以下m行每行输入三个正整数x,y,z,表示标号为x的人和标号为y的人之间互相转账需要扣除z%的手续费 (z<100)。
最后一行输入两个正整数A,B。数据保证A与B之间可以直接或间接地转账。
输出格式:输出A使得B到账100元最少需要的总费用。精确到小数点后8位。

明确的思路:将b点看作起点,求出路径的最大值(因为权值即真正到手的费用在总费用中的占比,在最后100/路径最大值,得到的就是A花费的最少钱了。
也是很沧桑的代码。
仍然是一往无前的bmf。

#include<bits/stdc++.h>
using namespace std;

struct edge
{
    int q,z;
    double v;
}e[2000050];
int n,m,a,b;
int tot=0;
double dis[2050];

void read(int &x)
{
    int f=1;x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    x*=f;
    return;
}//从百度摘下的ctrl+c+v的读入优化,以后要记住。虽然不知道有没有用,但是毕竟用bmf有点虚。

void bmf()
{
    for(int i=1;i<=n;i++) dis[i]=-1;//以前求最短路径,是将每个点设作无穷大,而现在求最大值,当然所有数据都不会小于零,那么初值只要-1就够了。
    dis[b]=1;//血泪的教训,后面用的是乘法,这里初值赋零就gg了。其实更好的方式是理解,求最短路的题赋零是因为b点到b点距离为零,而这里则是b给b转账时,真实到手的费用即总费用。
    for(int i=1;i<=n;i++)
    {
        int flag=0;
        for(int j=1;j<=tot;j++)
            if(1.0*e[j].v*dis[e[j].q]>1.0*dis[e[j].z])
                dis[e[j].z]=1.0*e[j].v*dis[e[j].q],flag=1;//乘法乘法乘法乘法……
        if(flag==0) break;//判断松弛结束的一个小小的优化。
    }
    return;
}
int main()
{
    read(n);read(m);//真的不会用输入优化,一开始很愚蠢地调用这个函数之后又加了句scanf,………………
    for(int i=1;i<=m;i++)
    {
        int x,y,v;
        read(x);read(y);read(v);
        e[++tot].q=x;e[tot].z=y;e[tot].v=1.0*(100-v)/100;//真正到手的金额占总费用比。
        e[++tot].q=y;e[tot].z=x;e[tot].v=1.0*(100-v)/100;
    }
    read(a);read(b);
    bmf();
    printf("%.8lf",1.0*100/(dis[a]));//快乐又美妙的输出时间!
    return 0;
}

一件更尴尬的事,我发现我仍然没有记清楚格式符……
基础知识,有待加强。

还有道前几天的,忘记总结,一并放在这里。
luogu2835.刻录光盘。

floyed。

现在假设总共有N个营员(2<=N<=200),每个营员的编号为1~N。LHC给每个人发了一张调查表,让每个营员填上自己愿意让哪些人到他那儿拷贝资料。当然,如果A愿意把资料拷贝给B,而B又愿意把资料拷贝给C,则一旦A获得了资料,则B,C都会获得资料。
现在,请你编写一个程序,根据回收上来的调查表,帮助LHC计算出组委会至少要刻录多少张光盘,才能保证所有营员回去后都能得到夏令营资料?

#include<bits/stdc++.h>
using namespace std;

int n;
int a[250][250]={};
int b[250]={};//存这个人从哪儿拷贝的光盘。 
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        int x;
        for(int j=1;j<=n;j++)  
        {
            cin>>x;if(x==0) break;a[i][x]=1;
        }
        a[i][i]=1;b[i]=i;//初始当然是从自己这里拷贝的。 
    }
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(a[k][j]==1&&a[i][k]==1) a[i][j]=1;//可爱的floyed。 
    for(int i=1;i<=n;i++)
       for(int j=1;j<=n;j++)
          if(a[i][j]==1) b[j]=b[i];//如果a[i][j]=1,说明j能从i处拷贝。
    int Sum=0;//光盘数。 
    for(int i=1;i<=n;i++) 
        if(b[i]==i)  Sum++;//如果i位置存的仍是i,说明只能光盘++啦。
    cout<<Sum;
    return 0;
}

正经事做完,再感慨一句吧。
不管发生什么事,定位放稳,不要浮躁,也不要妄自菲薄。
像wnk说的,坚持走到最后。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值