這題的題目描述可謂是又臭又長,看了看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;
}