天天看點

POJ 3835 & HDU 3268 Columbus’s bargain(最短路 Spfa)

題目連結:

POJ:http://poj.org/problem?id=3835

HDU:http://acm.hdu.edu.cn/showproblem.php?pid=3268

Problem Description On the evening of 3 August 1492, Christopher Columbus departed from Palos de la Frontera with a few ships, starting a serious of voyages of finding a new route to India. As you know, just in those voyages, Columbus discovered the America continent which he thought was India.

Because the ships are not large enough and there are seldom harbors in his route, Columbus had to buy food and other necessary things from savages. Gold coins were the most popular currency in the world at that time and savages also accept them. Columbus wanted to buy N kinds of goods from savages, and each kind of goods has a price in gold coins. Columbus brought enough glass beads with him, because he knew that for savages, a glass bead is as valuable as a gold coin. Columbus could buy an item he need only in four ways below:

1.  Pay the price all by gold coins.

2.  Pay by ONE glass bead and some gold coins. In this way, if an item’s price is k gold coins, Columbus could just pay k – 1 gold coins and one glass bead.

3.  Pay by an item which has the same price.

4.  Pay by a cheaper item and some gold coins. 

Columbus found out an interesting thing in the trade rule of savages: For some kinds of goods, when the buyer wanted to buy an item by paying a cheaper item and some gold coins, he didn’t have to pay the price difference, he can pay less. If one could buy an item of kind A by paying a cheaper item of kind B plus some gold coins less than the price difference between B and A, Columbus called that there was a “bargain” between kind B and kind A. To get an item, Columbus didn’t have to spend gold coins as many as its price because he could use glass beads or took full advantages of “bargains”. So Columbus wanted to know, for any kind of goods, at least how many gold coins he had to spend in order to get one – Columbus called it “actual price” of that kind of goods. 

Just for curiosity, Columbus also wanted to know, how many kinds of goods are there whose “actual price” was equal to the sum of “actual price” of other two kinds.

Input There are several test cases. 

The first line in the input is an integer T indicating the number of test cases ( 0 < T <= 10).

For each test case:

The first line contains an integer N, meaning there are N kinds of goods ( 0 < N <= 20). These N kinds are numbered from 1 to N.

Then N lines follow, each contains two integers Q and P, meaning that the price of the goods of kind Q is P. ( 0 <Q <=N, 0 < P <= 30 )

The next line is a integer M( 0 < M <= 20 ), meaning there are M “bargains”. 

Then M lines follow, each contains three integers N1, N2 and R, meaning that you can get an item of kind N2 by paying an item of kind N1 plus R gold coins. It’s guaranteed that the goods of kind N1 is cheaper than the goods of kind N2 and R is none negative and less than the price difference between the goods of kind N2 and kind N1. Please note that R could be zero. 

Output For each test case:

Please output N lines at first. Each line contains two integers n and p, meaning that the “actual price” of the goods of kind n is p gold coins. These N lines should be in the ascending order of kind No. . 

Then output a line containing an integer m, indicating that there are m kinds of goods whose “actual price” is equal to the sum of “actual price” of other two kinds.

Sample Input

1 4 1 4 2 9 3 5 4 13 2 1 2 3 3 4 6  

Sample Output

1 3 2 6 3 4 4 10 1  

Source 2009 Asia Ningbo Regional Contest Hosted by NIT

題意:

哥倫布和别人交易,用金币,交易規則:

1、每次買一個東西能夠用一個玻璃珠取代1金币。

2、能夠用同樣的價格物品進行交換

3、假設對方願意能夠用N1+r金币交換到N2物品。

求最後每件物品的最小價格,而且最後輸出有多少個物品價格=其它兩個物品價格和。

PS:

首先建立一個源點S,然後連接配接全部的點,邊上的權值為最初的價錢p - 1,然後在可用來交易的物品間建邊,權值為R,然後價錢相等的物品再建邊,權值為 0 ,求以S為源點的單源多點最短路;

代碼例如以下:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <climits>
#include <ctype.h>
#include <queue>
#include <stack>
#include <vector>
#include <deque>
#include <set>
#include <map>
#include <iostream>
#include <algorithm>
using namespace std;
#define pi acos(-1.0)
#define INF 0xffffff
#define N 1005
#define M 2005
int n,m,k,Edgehead[N],dis[N];
struct
{
    int v,w,next;
} Edge[2*M];
bool vis[N];
int vv[N];
int cont[N];
void Addedge(int u,int v,int w)
{
    Edge[k].next = Edgehead[u];
    Edge[k].w = w;
    Edge[k].v = v;
    Edgehead[u] = k++;
}
void SPFA( int start)
{
    queue<int>Q;
    for(int i = 1 ; i <= n ; i++ )
        dis[i] = INF;
    dis[start] = 0;
    ++cont[start];
    memset(vis,false,sizeof(vis));
    Q.push(start);
    while(!Q.empty())//直到隊列為空
    {
        int u = Q.front();
        Q.pop();
        vis[u] = false;
        for(int i = Edgehead[u] ; i!=-1 ; i = Edge[i].next)//注意
        {
            int v = Edge[i].v;
            int w = Edge[i].w;
            if(dis[v] > dis[u] + w)
            {
                dis[v] = dis[u]+w;
                if( !vis[v] )//防止出現環,也就是進隊列反複了
                {
                    Q.push(v);
                    vis[v] = true;
                }
                //	if(++cont[v] > n)//有負環
                //		return -1;
            }
        }
    }
    //return dis[n];
}
int main()
{
    int t;
    int u,v,w;
    int n1, n2, r;
    int a, p;

    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        //scanf("%d%d",&m,&n);//n為目的地
        k = 1;
        memset(Edgehead,-1,sizeof(Edgehead));
        memset(vv,0,sizeof(vv));
        for(int i = 1; i <= n; i++)
        {
            scanf("%d%d",&a,&p);
            vv[a] = p;
            Addedge(0,a,p-1);
        }
        scanf("%d",&m);
        for(int i = 1 ; i <= m ; i++ )
        {
            scanf("%d%d%d",&u,&v,&w);
            Addedge(u,v,w);
            //Addedge(v,u,w);//雙向連結清單
        }
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= n; j++)
            {
                if(i!=j && vv[i]==vv[j])//價錢相等
                {
                    Addedge(i,j,0);//價錢相等權值就是零
                    Addedge(j,i,0);
                }
            }
        }
        SPFA(0);//從點0開始尋找最短路
        for(int i = 1; i <= n; i++)
        {
            printf("%d %d\n",i,dis[i]);
        }
        memset(vis,0,sizeof(vis));
        int num = 0;
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= n; j++)
            {
//                if(i != j)
//                {
                for(int k = j+1; k <= n; k++)
                {
                    if(i != j)
                    {
                        if(!vis[i] && i!=k && dis[i]==dis[j]+dis[k])
                        {
                            vis[i] = true;
                            num++;
                        }
                    }
                }
            }
//            }
        }
        printf("%d\n",num);
    }
    return 0;
}