PAT L3-017. 森森快遞


L3-017. 森森快遞

時間限制
400 ms
內存限制
65536 kB
代碼長度限制
8000 B
判題程序
Standard
作者
俞勇(上海交通大學)

森森開了一家快遞公司,叫森森快遞。因為公司剛剛開張,所以業務路線很簡單,可以認為是一條直線上的N個城市,這些城市從左到右依次從0到(N-1)編號。由於道路限制,第i號城市(i=0, ..., N-2)與第(i+1)號城市中間往返的運輸貨物重量在同一時刻不能超過 Ci公斤。

公司開張后很快接到了Q張訂單,其中第j張訂單描述了某些指定的貨物要從Sj號城市運輸到Tj號城市。這里我們簡單地假設所有貨物都有無限貨源,森森會不定時地挑選其中一部分貨物進行運輸。安全起見,這些貨物不會在中途卸貨。

為了讓公司整體效益更佳,森森想知道如何安排訂單的運輸,能使得運輸的貨物重量最大且符合道路的限制?要注意的是,發貨時間有可能是任何時刻,所以我們安排訂單的時候,必須保證共用同一條道路的所有貨車的總重量不超載。例如我們安排1號城市到4號城市以及2號城市到4號城市兩張訂單的運輸,則這兩張訂單的運輸同時受2-3以及3-4兩條道路的限制,因為兩張訂單的貨物可能會同時在這些道路上運輸。

輸入格式:

輸入在第一行給出兩個正整數N和Q(2 <= N <= 105, 1 <= Q <= 105),表示總共的城市數以及訂單數量。

第二行給出(N-1)個數,順次表示相鄰兩城市間的道路允許的最大運貨重量Ci(i=0, ..., N-2)。題目保證每個Ci是不超過231的非負整數。

接下來Q行,每行給出一張訂單的起始及終止運輸城市編號。題目保證所有編號合法,並且不存在起點和終點重合的情況。

輸出格式:

在一行中輸出可運輸貨物的最大重量。

輸入樣例:
10 6
0 7 8 5 2 3 1 9 10
0 9
1 8
2 7
6 3
4 5
4 2
輸出樣例:
7
樣例提示:我們選擇執行最后兩張訂單,即把5公斤貨從城市4運到城市2,並且把2公斤貨從城市4運到城市5,就可以得到最大運輸量7公斤。
 
用dfs水了15分,開始用wector做的,以為vector< pair<int,int> >E[maxn] 定義,可以直接通過E[x][y]訪問(x,y)邊,寫的差不多以后才發現不可以,每次增加是從零開始的,比如在1點添加5,6,你只能通過E[1][0],E[1][1]一次訪問(1,0),(1,1)邊。最后兩分鍾情急下用了數組水了15分
 
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<map>
#include<set>
#define maxn 10010
using namespace std;
typedef long long ll;
int edge[maxn][maxn];
vector<int> E[maxn];
ll ans = 0;
int vis[maxn] = {0};
void dfs( int x, ll sum ) {
    if( sum > ans ) {
        ans = sum;
    }
    for( int i = 0; i < E[x].size(); i ++ ) {
        if( !vis[E[x][i]] ) {
            vis[E[x][i]] = 1;
            dfs( E[x][i], sum + edge[x][E[x][i]] );
            vis[E[x][i]] = 0;
        }
    }
}
int main() {
    int n, m, a[maxn], t = 1e9;
    cin >> n >> m;
    for( int i = 0; i < n - 1; i ++ ) {
        cin >> a[i];
       /* edge[i].push_back( make_pair( i + 1, a[i] ) );
        edge[i+1].push_back( make_pair( i, a[i] ) );*/
        edge[i][i+1] = a[i];
        edge[i+1][i] = a[i];
        for( int j = 0; j < i - 1; j ++ ) {
            t = 1e9;
            for( int k = j; k < i; k ++ ) {
                t = min( t, a[k] );
            }
            /*edge[j].push_back( make_pair( i, t ) );
            edge[i].push_back( make_pair( j, t ) );*/
            edge[i][j] = t;
            edge[j][i] = t;
        }
    }
    while( m -- ) {
        int x, y;
        cin >> x >> y;
        E[x].push_back(y);
        E[y].push_back(x);
    }
    for( int i = 0; i <= n - 1; i ++ ) {
        /*for( int j = 0; j < E[i].size(); j ++ ) {
            cout << E[i][j] << " " << edge[i][E[i][j]] << "--";
        }
        cout << endl;*/
        memset( vis, 0, sizeof(vis) );
        vis[i] = 1;
        dfs( i, 0 );
    }
    cout << ans - 1 << endl;
    return 0;
}

 

比賽后看大佬用線段樹+貪心做的

https://blog.csdn.net/hnust_derker/article/details/79552988

 

/** 
因為一個區間[l, r]的最大貨運量就是min([l, r]), 對於兩個區間[l, r], [L, R] 假設(r <= R) 
1. 兩個區間完全不相交, 則最大貨運量就是min([l, r]) + min([L, R]),誰先取誰后取都是一樣 
 
2.[l, r]完全包含於[L, R],那么肯定選擇[l, r]且取其最大貨運量,因為min[l, r] >= min[L, R],如果選擇兩個訂單的話,最大貨運量都 
是min[l, r], 但是單獨取[l, r]這個區間, 那么對周圍影響的區間都小, 往左往右才可能有更優的取值, 如果[L, R]這個區間要取的話, 
這里的每個值都要減去一個值,且最終[l, r]的結果是一樣的, 所以肯定取[l,r]且保證貨運量最大 
 
3.兩區間相交,如果若干個區間已經按右端點從小到大排好序,相同按左端點排序,假設相交於[L, r], 那么兩個區間的最大值就是 
min{min[L, r], min[l, r] + min[L, R]}這個值是不變的,但是如果[L, R]取得大的話, 對后面的可能相交區間最小值影響就大, 所以要對 
l, r取盡可能大, L, R取盡可能小 
 
所以就是: 區間已經按右端點從小到大排好序,相同按左端點排序, 然后從左往右,遇到一個區間就取其區間最小值加到ans上去, 然后更新這個區間 
*/  
  
#include<bits/stdc++.h>  
typedef long long ll;  
const ll maxn = 2e5 + 10;  
const ll INF = 1e10;  
using namespace std;  
  
  
typedef pair<ll, ll> pa;  
ll n, m, T, kase = 1;  
ll C[maxn * 4], lazy[maxn * 4], d[maxn];  
pa lst[maxn];  
  
void push_down(ll o) {  
    ll o1 = o << 1, o2 = o << 1 | 1;  
    if(!lazy[o]) return ;  
    lazy[o1] += lazy[o]; lazy[o2] += lazy[o];  
    C[o1] -= lazy[o]; C[o2] -= lazy[o]; lazy[o] = 0;  
}  
  
void build(ll o, ll l, ll r) {  
    lazy[o] = 0;  
    if(l == r) { C[o] = d[l]; return ; }  
    ll mid = (l + r) >> 1;  
    build(o << 1, l, mid);  
    build(o << 1 | 1, mid + 1, r);  
    C[o] = min(C[o << 1], C[o << 1 | 1]);  
}  
  
ll ql, qr, data;  
ll query_min(ll o, ll l, ll r) {  
    if(l >= ql && r <= qr) return C[o];  
    if(l > qr || r < ql) return INF;  
    ll mid = (l + r) >> 1;  
    push_down(o);  
    ll p1 = query_min(o << 1, l, mid);  
    ll p2 = query_min(o << 1 | 1, mid + 1, r);  
    C[o] = min(C[o << 1], C[o << 1 | 1]);  
    return min(p1, p2);  
}  
  
void update(ll o, ll l, ll r) {  
    if(l >= ql && r <= qr) {  
        C[o] -= data; lazy[o] += data;  
        return ;  
    }  
    if(l > qr || r < ql) return ;  
    push_down(o);  
    ll mid = (l + r) >> 1;  
    update(o << 1, l, mid);  
    update(o << 1 | 1, mid + 1, r);  
    C[o] = min(C[o << 1], C[o << 1 | 1]);  
}  
  
int main() {  
    while(scanf("%lld %lld", &n, &m) != EOF) {  
        for(ll i = 0; i < n - 1; i++) scanf("%lld", &d[i]);  
        build(1, 0, n - 2);  
        for(ll i = 0; i < m; i++) {  
            scanf("%lld %lld", &ql, &qr);  
            if(ql > qr) swap(ql, qr); qr--;  
            lst[i] = pa(qr, ql);  
        }  
        ll ans = 0; sort(lst, lst + m);  
        for(int i = 0; i < m; i++) {  
            ql = lst[i].second; qr = lst[i].first;  
            ll mt = query_min(1, 0, n - 2);  
            ans += mt; data = mt; update(1, 0, n - 2);  
        }  
        printf("%lld\n", ans);  
    }  
    return 0;  
}  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM