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

来源:互联网 发布:男友那个很大 知乎 编辑:程序博客网 时间:2024/06/08 01:53

我迷上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说的,坚持走到最后。

原创粉丝点击