1. 程式人生 > >[DP] [1D1D優化] [樹狀陣列] [最短路] 遭遇戰 (clean)

[DP] [1D1D優化] [樹狀陣列] [最短路] 遭遇戰 (clean)

背景 Background

你知道嗎,SQ Class的人都很喜歡打CS。(不知道CS是什麼的人不用參加這次比賽)。

題目描述 Description

今天,他們在打一張叫DUSTII的地圖,萬惡的恐怖分子要炸掉藏在A區的SQC論壇伺服器!我們SQC的人誓死不屈,即將於恐怖分子展開激戰,準備讓一個人守著A區,這樣恐怖分子就不能炸掉伺服器了。(一個人就能守住??這人是機械戰警還是霹靂遊俠?)
但是問題隨之出現了,由於DustII中風景秀麗,而且不收門票,所以n名反恐精英們很喜歡在這裡散步,喝茶。他們不願意去單獨守在荒無人煙的A區,在指揮官的一再命令下,他們終於妥協了,但是他們每個人都要求能繼續旅遊,於是給出了自己的空閒時間,而且你強大的情報系統告訴了你恐怖份子計劃的進攻時間(從s

時刻到e時刻)。
當然,精明的SQC成員不會為你免費服務,他們還要收取一定的佣金(注意,只要你聘用這個隊員,不論他的執勤時間多少,都要付所有被要求的佣金)。身為指揮官的你,看看口袋裡不多的資金(上頭真摳!),需要安排一個計劃,僱傭一些隊員,讓他們在保證在進攻時間裡每時每刻都有人員執勤,花費的最少資金。

輸入 Input

第一行是三個整數n(1n10000)se1se90000
接下來n行,描述每個反恐隊員的資訊:空閒的時間si,ei1siei90000和佣金ci1ci300000

輸出 Output

一個整數,最少需支付的佣金,如果無解,輸出“1”。

樣例輸入 Sample Input

3 1 5
1 3 3
4 5 2
1 1 1

樣例輸出 Sample Output

5

提示 Hints

敵人從1時刻到4時刻要來進攻,一共有3名反恐隊員。第1名從1時刻到3時刻有空,要3元錢(買糖都不夠??)。以此類推。
一共要付5元錢,選用第1名和第2名。

限制 Limits

資料範圍見題目
Time Limit : 1s & Memory Limit : 128MB

首先我要吐槽一下題目解釋,根本物理沒學好好嗎?時間是區間而時刻是點好嗎?解釋一下是打錯了還是怎麼回事(物理老師閃現)
看題,明顯的帶權值線段覆蓋,DP可以解決權值為1

的線段覆蓋問題。
思路就是列舉a起點,在a起點的終點之前找到與之覆蓋的b起點,b起點覆蓋的最小代價已經求出,加上a線段的權值就可以了
那麼就有一個嚴重的問題
求最小值列舉就是個T的,在來個TT2?可以T
那麼就搞個什麼東西維護一下這個DP陣列
搞定區間最小值直接上樹狀陣列,O(n+Tlog2T)的時間非常好
上程式碼
Code
(UPD:這好像是我寫的第一個1D1D……)
但是……
還好吧,考場上絕對想不出來
下面就是一個非常優(tou)秀(ji)的方法:轉化成圖論題
時間區間可以看成從開始到結束的一條邊,權值就是邊權
為了使圖聯通,可以反向加邊,即i+1時刻到i時刻有一條邊權為0的邊
上程式碼

#include <queue>
#include <cstdio>
#include <cstring>
#include <climits>
#define MAXN 100100
#define MAXT 900100
using namespace std;

struct link
{
    int to;
    int val;
    int nxt;
};

link e[MAXN+MAXT];
int e_num[MAXN],cnt;
int n,s,t;
int start,finish;
int u,v,w;
int dis[MAXT],vis[MAXT];
queue <int> q;

int mymax(int a,int b)
{
    return a>b?a:b;
}

int mymin(int a,int b)
{
    return a<b?a:b;
}

void add(int u,int v,int w)
{
    e[cnt]=(link){v,w,e_num[u]}; e_num[u]=cnt++;
}

int spfa()
{
    dis[s]=0;vis[s]=true;q.push(s);
    while (!q.empty())
    {
        int u=q.front();q.pop();vis[u]=false;
        for (int i=e_num[u];i!=-1;i=e[i].nxt)
        {
            if (dis[e[i].to]>dis[u]+e[i].val)
            {
                dis[e[i].to]=dis[u]+e[i].val;
                if (!vis[e[i].to])
                {
                    vis[e[i].to]=true;
                    q.push(e[i].to);
                }
            }
        }
    }
    if (dis[t]==INT_MAX) return -1;
    else return dis[t+1];
}

int main()
{
    memset(vis,false,sizeof(vis));
    memset(e_num,-1,sizeof(e_num));
    scanf("%d %d %d",&n,&s,&t);
    for (int i=1;i<=n;i++)
    {
        scanf("%d %d %d",&u,&v,&w);
        add(mymax(u,s),mymin(v,t)+1,w);
    }
    for (int i=s;i<=t+1;i++)
    {
        add(i+1,i,0);
        dis[i]=INT_MAX;
    }
    printf("%d",spfa());
    return 0;
}

據說正解是堆優化?
下面是標程(pascal黨的福音)

const maxn=20000;
      maxt=100000;
type re=record
       data,pos:int64;
end;
var e,e2,i,n,t,t2,heapsize:longint;
    a:array [0..maxn,1..3] of int64;
    f:array [0..maxt] of int64;
    heap:array [0..maxn] of re;
procedure change(var a,b:re);
var temp:re;
begin
  temp:=a;
  a:=b;
  b:=temp;
end;
procedure insert(pos,data:int64);
var now,next:longint;
begin
  inc(heapsize);
  heap[heapsize].pos:=pos;
  heap[heapsize].data:=data;
  now:=heapsize;
  while now<>1 do
    begin
      next:=now div 2;
      if heap[now].data>=heap[next].data then exit;
      change(heap[now],heap[next]);
      now:=next;
    end;
end;
procedure delete;
var now,next:longint;
begin
  heap[1]:=heap[heapsize];
  heap[heapsize].data:=0;
  heap[heapsize].pos:=0;
  dec(heapsize);
  now:=1;
  while now*2<=heapsize do
    begin
      next:=now*2;
      if (next<heapsize)and(heap[next+1].data<heap[next].data) then inc(next);
      if heap[now].data<=heap[next].data then exit;
      change(heap[now],heap[next]);
      now:=next;
    end;
end;
procedure work;
var i:longint;
begin
  heapsize:=1;
  heap[1].data:=0;
  heap[1].pos:=0;
  fillchar(f,sizeof(f),0);
  for i:=1 to n do
    begin
      while (heapsize>0)and(heap[1].pos<a[i,1]-1) do delete;
        if heapsize=0 then
          begin
            writeln(-1);
            exit;
          end;
        if (heap[1].data+a[i,3]<f[a[i,2]])or(f[a[i,2]]=0) then
          begin
            f[a[i,2]]:=heap[1].data+a[i,3];
            insert(a[i,2],heap[1].data+a[i,3]);
          end;
      end;
  if f[t]=0 then writeln(-1)
  else writeln(f[t]);
end;
procedure sor(x,y:longint);
var i,k:longint;
begin
  for i:=1 to 3 do
    begin
      k:=a[x,i];
      a[x,i]:=a[y,i];
      a[y,i]:=k;
    end;
end;
procedure sort(l,r:longint);
var i,j:longint;
begin
  i:=l;
  j:=r;
  while i<j do
    begin
      while (i<j)and((a[i,1]<a[j,1])or(a[i,1]=a[j,1])and(a[i,2]<=a[j,2])) do j:=j-1;
      sor(i,j);
      while (i<j)and((a[i,1]<a[j,1])or(a[i,1]=a[j,1])and(a[i,2]<=a[j,2])) do i:=i+1;
      sor(i,j);
    end;
  if l<i-1 then sort(l,i-1);
  if j+1<r then sort(j+1,r);
end;
begin
  readln(n,e2,t2);
  e:=e2-1;
  t:=t2-e;
  for i:=1 to n do
    begin
      readln(a[i,1],a[i,2],a[i,3]);
      if a[i,1]<e2 then a[i,1]:=e2;
      if a[i,2]>t2 then a[i,2]:=t2;
      a[i,1]:=a[i,1]-e;
      a[i,2]:=a[i,2]-e;
    end;
  sort(1,n);
  work;
end.

DP裡優(xia)化(gao)真神奇……