[USACO13DEC]假期计划(黄金)Vacation Planning (gold)

[USACO13DEC]假期计划(黄金)Vacation Planning (gold)

题目描述

Air Bovinia operates flights connecting the N farms that the cows live on (1 <= N <= 20,000). As with any airline, K of these farms have been designated as hubs (1 <= K <= 200, K <= N).

Currently, Air Bovinia offers M one-way flights (1 <= M <= 20,000), where flight i travels from farm u_i to farm v_i and costs d_i (1 <= d_i <= 10,000) dollars. As with any other sensible airline, for each of these flights, at least one of u_i and v_i is a hub. There is at most one direct flight between two farms in any given direction, and no flight starts and ends at the same farm.

Bessie is in charge of running the ticketing services for Air Bovinia. Unfortunately, while she was away chewing on delicious hay for a few hours, Q one-way travel requests for the cows' holiday vacations were received (1 <= Q <= 50,000), where the ith request is from farm a_i to farm b_i.

As Bessie is overwhelmed with the task of processing these tickets, please help her compute whether each ticket request can be fullfilled, and its minimum cost if it can be done.

To reduce the output size, you should only output the total number of ticket requests that are possible, and the minimum total cost for them. Note that this number might not fit into a 32-bit integer.

是n个点m条有向边,求两两之间的最短路,要求路径上必须经过编号1~k的至少一个点

输入输出格式

输入格式:

 

  • Line 1: The integers N, M, K, and Q.

  • Lines 2..M + 1: Line i+1 contains u_i, v_i, and d_i. (1 <= u_i, v_i <= N, u_i != v_i)

  • Lines M + 2..M + K + 1: Each of these lines contains the ID of a single hub (in the range 1..N).

  • Lines M + K + 2..M + K + Q + 1: Two numbers per line, indicating a request for a ticket from farm a_i to b_i. (1 <= a_i, b_i <= N, a_i != b_i)

 

输出格式:

 

  • Line 1: The number of ticket requests that can be fullfilled.

  • Line 2: The minimum total cost of fulling the possible ticket requests

 

输入输出样例

输入样例#1:
3 3 1 2 
1 2 10 
2 3 10 
2 1 5 
2 
1 3 
3 1 
输出样例#1:
1 
20 

说明

For the first flight, the only feasible route is 1->2->3, costing 20. There are no flights leaving farm 3, so the poor cows are stranded there.

题目大意

他发现整个地图中有N(1<=N<=20000)个地点。对于所有的路线,指定了其中K(1<=K<=200,K<=N)个地点作为收费站。他设计了M(1<=M<=20000 )种单向的路线,第i条路线从地点Ui至Vi收费为Di(1<=Di<=10000)。路线保证Ui或Vi至少有一个是收费站,且Ui≠Vi,任意两个地点至多有一条路线。现在Awson准备进行规划。共提出Q(1<=Q<=50000)个询问,其中第i个询问是从地点Ai至地点Bi。请帮助他计算,每个请求是否满足(是否从地点Ai至地点Bi有可行路线),并计算:能满足的度假询问的最小费用总和。

题解:

法一:

显然是一道求多源最短路的题,而总的点数远远超过了floyd的承受范围。

我们用分治的思想,注意到题中所有边都是与“关键点”即收费站相连的,显然我们可以考虑对于这些点进行floyd。

对于非关键点的点,我们可以枚举,并在之前floyd处理完的“块”内求一遍单源最短路,注意与枚举的点相连的边是“出边”还是“入边”。

处理答案时,注意点要分是在“块”内还是“块”外。

法二:

spfa求出每个关键点到每一个点的距离,然后查找时有两种情况。

1.from为关键点,直接输出from到to的距离。

2.from不为关键点,那么根据题意与from相连的所有点都是关键点,所以枚举每一个关键点求一个最小值再加上from到这个关键点的距离就可以了。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
int n,m,k,q,cnt,ans,tot;
int head[20005],kk[20005],size=1;
struct node
{
    int next,to,dis;
}edge[20005];
void putin(int from,int to,int dis)
{
    size++;
    edge[size].to=to;
    edge[size].dis=dis;
    edge[size].next=head[from];
    head[from]=size;
}
int dist[201][20005];
bool vis[20005];
void spfa(int r)
{
    int i;
    queue<int>mem;
    memset(vis,0,sizeof(vis));
    mem.push(r);
    vis[r]=1;
    dist[kk[r]][r]=0;
    while(!mem.empty())
    {
        int x=mem.front();mem.pop();
        vis[x]=0;
        for(i=head[x];i!=-1;i=edge[i].next)
        {
            int y=edge[i].to;
            if(dist[kk[r]][y]>dist[kk[r]][x]+edge[i].dis)
            {
                dist[kk[r]][y]=dist[kk[r]][x]+edge[i].dis;
                if(!vis[y])
                {
                    mem.push(y);
                    vis[y]=1;
                }
            }
        }
    }
}
int main()
{
    int i,j;
    memset(head,-1,sizeof(head));
    scanf("%d%d%d%d",&n,&m,&k,&q);
    for(i=1;i<=m;i++)
    {
        int from,to,dis;
        scanf("%d%d%d",&from,&to,&dis);
        putin(from,to,dis);
    }
    memset(dist,127/3,sizeof(dist));
    int kkk;
    for(i=1;i<=k;i++)
        scanf("%d",&kkk),kk[kkk]=++tot,spfa(kkk);
    for(i=1;i<=q;i++)
    {
        int from,to;
        scanf("%d%d",&from,&to);
        if(kk[from]&&dist[kk[from]][to]!=dist[0][0])cnt++,ans+=dist[kk[from]][to];
        else
        {
            int mmin=dist[0][0];
            for(j=head[from];j!=-1;j=edge[j].next)
            {
                int y=edge[j].to;
                mmin=min(mmin,edge[j].dis+dist[kk[y]][to]);
            }
            if(mmin!=dist[0][0])cnt++,ans+=mmin;
        }
    }
    printf("%d\n%d\n",cnt,ans);
    return 0;
}

 

 

 

 

转载于:https://www.cnblogs.com/huangdalaofighting/p/7365798.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值