[DP] [1D1D優化] [樹狀陣列] [最短路] 遭遇戰 (clean)
背景 Background
你知道嗎,SQ Class的人都很喜歡打CS。(不知道CS是什麼的人不用參加這次比賽)。
題目描述 Description
今天,他們在打一張叫DUSTII的地圖,萬惡的恐怖分子要炸掉藏在A區的SQC論壇伺服器!我們SQC的人誓死不屈,即將於恐怖分子展開激戰,準備讓一個人守著A區,這樣恐怖分子就不能炸掉伺服器了。(一個人就能守住??這人是機械戰警還是霹靂遊俠?)
但是問題隨之出現了,由於DustII中風景秀麗,而且不收門票,所以n 名反恐精英們很喜歡在這裡散步,喝茶。他們不願意去單獨守在荒無人煙的A區,在指揮官的一再命令下,他們終於妥協了,但是他們每個人都要求能繼續旅遊,於是給出了自己的空閒時間,而且你強大的情報系統告訴了你恐怖份子計劃的進攻時間(從s 時刻到e 時刻)。
當然,精明的SQC成員不會為你免費服務,他們還要收取一定的佣金(注意,只要你聘用這個隊員,不論他的執勤時間多少,都要付所有被要求的佣金)。身為指揮官的你,看看口袋裡不多的資金(上頭真摳!),需要安排一個計劃,僱傭一些隊員,讓他們在保證在進攻時間裡每時每刻都有人員執勤,花費的最少資金。
輸入 Input
第一行是三個整數
n(1≤n≤10000) ,s 和e(1≤s≤e≤90000) 。
接下來n 行,描述每個反恐隊員的資訊:空閒的時間si,ei(1≤si≤ei≤90000) 和佣金ci(1≤ci≤300000) 。
輸出 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可以解決權值為
思路就是列舉
那麼就有一個嚴重的問題
求最小值列舉就是個
那麼就搞個什麼東西維護一下這個DP陣列
搞定區間最小值直接上樹狀陣列,
上程式碼
Code
(UPD:這好像是我寫的第一個1D1D……)
但是……
還好吧,考場上絕對想不出來
下面就是一個非常優(tou)秀(ji)的方法:轉化成圖論題
時間區間可以看成從開始到結束的一條邊,權值就是邊權
為了使圖聯通,可以反向加邊,即
上程式碼
#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)真神奇……