【JZOJ3241】Money

本文介绍了一种在跨国公司中解决工资发放问题的算法。在不同国家使用不同货币的情况下,算法通过计算货币间的兑换关系,确定如何用现有货币支付员工工资,确保支付金额最接近应得工资且不超过货币持有上限。

description

你在一个跨国公司负责发工资,每个工人的工资以自己本国货币结算。如果你手头上有足够的该国货币,你就直接发给他;如果没有足够的该国货币,他也不介意收到其他种类的货币,前提是按兑换关系他没有少拿就可以了。例如,有六种货币:A,B,C,D,E,F,你知道这些货币的兑换关系是:

23 A = 17 B

16 C = 29 E

5 B = 14 E

1 D = 7 F

假如有个工人过来领100 A,而你手头正好没这么多A货币,你可以考虑替换成74 B(相当于100.12 A)、115 C(相当于100.72 A)或207 E(相当于100.02 A)。你应该支付207 E,因为这最接近这个工人应得的工资。

注意根据以上的兑换关系,你无法推断货币A与D、A与F的兑换关系。

由于钱仓空间有限,每种货币你最多只能持有100000,因此你无法用E货币支付64000 A,但用73078 C来支付是允许的。

假设工人领工资时,你正好没有结算的货币了,但其他货币的钱仓都是满的。你需要写一个程序帮你计算该怎样支付这个工人的工资。


analysis

  • 随便搞

  • 用遍历,搞出两两货币兑换的最小公倍数

  • 然后换就好了

  • 注意这题读入挺坑的…


code

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#define ll long long
#define INF 1000000007
#define fo(i,a,b) for (ll i=a;i<=b;++i)
#define fd(i,a,b) for (ll i=a;i>=b;--i)

using namespace std;

ll f[20][20][2],g[20][20][2];
char st[15],name[15],str[15][15];
ll n,tot,val,type,ans,now;
double mn=INF;
bool bz[20];

inline ll read()
{
	ll x=0,f=1;char ch=getchar();
	while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
	while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
	return x*f;
}
inline bool judge(char st1[],char st2[])
{
	ll len1=strlen(st1),len2=strlen(st2);
	if (len1!=len2)return 0;
	fo(i,0,len1-1)if (st1[i]!=st2[i])return 0;
	return 1;
}
inline ll query(char st[])
{
	fo(i,1,8)
	{
		if (strlen(str[i])==0)
		{
			++tot,strcpy(str[i],st);
			return i;
		}
		if (judge(st,str[i]))return i;
	}
}
inline ll gcd(ll x,ll y){return x%y==0?y:gcd(y,x%y);}
inline ll lcm(ll x,ll y){return x/gcd(x,y)*y;}
inline void dfs(ll x)
{
	bz[x]=0;
	fo(i,1,tot)if (f[x][i][0] && bz[i])
	{
		g[type][i][0]=g[type][x][0]*(lcm(g[type][x][1],f[x][i][0])/g[type][x][1]);
		g[type][i][1]=f[x][i][1]*(lcm(g[type][x][1],f[x][i][0])/f[x][i][0]);
		dfs(i);
	}
}
int main()
{
	n=read(),memset(bz,1,sizeof(bz));
	fo(i,1,n)
	{
		ll x=0,y=0,xx=0,yy=0,len=0;
		scanf("%s",&st),len=strlen(st);
		fo(i,0,len-1)x=x*10+st[i]-'0';
		scanf("%s",&st),len=strlen(st);
		xx=query(st);
		scanf("%s",&st),scanf("%s",&st),len=strlen(st);
		fo(i,0,len-1)y=y*10+st[i]-'0';
		scanf("%s",&st),len=strlen(st);
		yy=query(st);
		f[xx][yy][0]=x,f[xx][yy][1]=y;
		f[yy][xx][0]=y,f[yy][xx][1]=x;
	}
	val=read(),scanf("%s",&name),bz[type=query(name)]=0;
	fo(i,1,tot)if (type!=i && f[type][i][0])g[type][i][0]=f[type][i][0],g[type][i][1]=f[type][i][1],dfs(i);
	fo(i,1,tot)if (type!=i && g[type][i][0])
	{
		ll tmp=ceil(1.0*g[type][i][1]/g[type][i][0]*val);
		if (1.0*tmp*g[type][i][0]/g[type][i][1]-val<mn && tmp<=100000)
		mn=1.0*tmp*g[type][i][0]/g[type][i][1]-val,ans=tmp,now=i;
	}
	printf("%lld %s\n",ans,str[now]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值