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