这题的题目描述可谓是又臭又长,看了看source,卧槽!居然还是当年区域赛宁波赛区的。。。仅仅是因为题目的理解,让明明很简单的一道水spfa题WA了我一个下午。唉,算了,不吐槽了,要怪就怪我没能够静下心来好好读题,现在把题意明明白白地写在这里,供以后自省:
哥伦布桑麻发现了新大陆,然后他想拿黄金换一点新大陆的好东♂西思密达。但是新大陆的劳动人民有着非常奇特的交易规则,对于每件物品,哥伦布可以有三种交易方式:1.直接拿等值的黄金去交换物品 2.拿等值黄金去交换物品,但可以再拿一个玻璃珠去抵一个黄金(注意:只能用一个玻璃珠)3.拿一个便宜的物品,加上一些黄金去兑换一些价值更高的物品(这也是形成差价的关键)4.用一个等值的物品去兑换另一个物品。
输入每个物品的价格,然后再输入某个物品去兑换另一个物品时所需要补充的黄金个数。
输出要买到某个物品,最少需要花的钱数。
这么一看下来,只有⑨才会用第一种方法交换物品,嗯。。。是的。。。然后可以这样建图:设一个源点,那么这个源点到各个物品的最短距离就是物品的需要花的最少的钱数。源点到各个物品的边的权值就是物品的实际价格 - 1 (因为你不是⑨所以你肯定要选择用玻璃珠抵一个黄金),同时,可以兑换的物品,从便宜到贵的连一条单向边,边的权值就是需要补充的黄金价格。别忘了,等值的物品之间连一个双向边,权值为0(我在这上面不懂WA了多少次。。。)最后对每个节点用spfa求最短路就可以了。因为节点的个数不是很多,所以我也没有用边集数组,直接用邻接表去建的图。下面直接上代码:
不对。。。这题还要输出一个东西,就是actual price等于另外两个物品的actual price的和的物品。我草草草草。。。话说这个输出是在卖萌么?我忍不住吐槽:麻麻~这个问题和前面的问题画风不一样啊~
总之,这道题真是槽点满满,下面正式附上代码:
#include <stdio.h>
#include <stdlib.h>
int t,n,m,n1,n2,r,ma[30][30],v[30],hash[30];
void spfa()
{
int i,j,k,d[300],f,r;
f=1;r=1; d[1]=0;
while(f<=r)
{
for(i=1;i<=n;i++)
{
if((v[i]>v[d[f]]+ma[d[f]][i]))
{
v[i]=v[d[f]]+ma[d[f]][i];
r++;
d[r]=i;
}
}
f++;
}
}
int main()
{
int i,j,k,q,p,ans;
scanf("%d",&t);
while(t--)
{
ans=0;
scanf("%d",&n);
for(i=0;i<=n;i++)
for(j=0;j<=n;j++)
ma[i][j]=5000000;
for(i=0;i<=n;i++)
{
v[i]=5000000;
hash[i]=0;
}
v[0]=0;
for(i=1;i<=n;i++)
{
scanf("%d%d",&q,&p);
ma[0][q]=p-1;
}
for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++)
{
if(ma[0][i]==ma[0][j])
{
ma[i][j]=0;
ma[j][i]=0;
}
}
scanf("%d",&m);
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&n1,&n2,&r);
ma[n1][n2]=r; //靠!题目上写注意R=0其实一点用都没有
}
spfa();
for(i=1;i<=n;i++)
printf("%d %d\n",i,v[i]);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
for(k=1;k<=n;k++)
{
if((i!=j)&&(j!=k)&&(i!=k))
{
if((v[i]==v[j]+v[k])&&(hash[i]==0)) //注意这里的判重,找到过以后不能重复计数。
{
hash[i]=1; //如果无序,请注意是两倍关系,不过这里有判重不需要
ans++;
}
}
}
printf("%d\n",ans);
}
return 0;
}