旅行线路

【题目描述】
贝西经营着一家旅行社,一天贝西带着几队游客沿着亚马逊河旅行,河的两边分布着一些景点,每个景点都对应着一个观赏值。景点间由一些穿过河流的道路相连(位于河流同一侧的景点间没有直接道路相连),贝西想要设计游客的旅行线路,使得该线路经过的景点的总的观赏值最大。
但是,贝西可能同时带着几个旅行团,贝西希望它给安排的旅行线路不能相交。
两条线路 (a <-> x) 和 (b <-> y) 出现如下情况之一就算相交:
if(a < b and y < x) or (a > b and x < y) or (a = b and x = y).
帮助贝西找出最佳旅行线路,贝西可以从任意景点开始,在任意景点结束。
【输入格式】
第一行,三个空格间隔的整数N (1 <= N <= 40,000), M (1 <=M <= 40,000), and R (0<= R <= 100,000) 。N表示河岸左边的景点数,M表示河岸右边的景点数,R表示道路的条数
接下来N行,每行一个整数,表示河岸左边对应景点的观赏值。
接下来M行,每行一个整数,表示河岸右边对应景点的观赏值。
接下来R行,每行两个空格间隔的整数X,Y,表示左岸的X号景点与右岸的Y号景点间有道路直接相连。
(0 <= 观赏值<= 40,000)
【输出格式】
一个整数,表示所求最大观赏值。
【样例输入】
3 2 4
1
1
5
2
2
1 1
2 1
3 1
2 2
【样例输出】
8
【分析】
首先可以看出这题不能用贪心解决。
一种比较明显的思路就是双重循环枚举两个点后DP,但是更明显的是这样做的时间复杂度根本不能承受。
联想到克鲁斯卡尔算法与普利姆算法的区别,我们想到以边作为状态。首先要排序(去除后效性),然后设f1[i]表示左边以i结尾的最大收益,f2[i]表示右边以i结尾的最大收益,状态转移方程就很明显了。
转移的时候注意用临时变量存储。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 40005
#define maxe 100005
typedef long long LL;
typedef pair<int,int> pii;
int n,m,k;
LL a[maxn],b[maxn],f1[maxn],f2[maxn];
pii e[maxe];
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=m;i++) scanf("%d",&b[i]);
    for(int i=1;i<=k;i++) scanf("%d%d",&e[i].first,&e[i].second);
    sort(e+1,e+k+1);
    memcpy(f1,a,sizeof(a));
    memcpy(f2,b,sizeof(b));
    for(int i=k;i>=1;i--) {
        int u=e[i].first,v=e[i].second;
        LL va=a[u]+f2[v];
        LL vb=b[v]+f1[u];
        f1[u]=max(f1[u],va);
        f2[v]=max(f2[v],vb);
    }
    int ans=0;
    for (int i=1;i<=n;i++) if (ans<f1[i]) ans=f1[i];
    for (int i=1;i<=m;i++) if (ans<f2[i]) ans=f2[i];
    cout<<ans;
    return 0;
}
posted @ 2016-11-05 14:27  JRX2015U43  阅读(152)  评论(0编辑  收藏  举报