bzoj1061(k可重區間集)
然而還是不能夠很好地理解線性規劃,因此再看了一下發現其實是k可重區間集問題。。
那麼建圖方向就有了。。然而這個題比較特殊,只有下界沒有上界,想跑上下界也不行了。。
因此可以把容量取反,下界就變成上界了。。然後由於網路流只接受正數流,因此要把取反之後的容量加上inf,然後原來的建圖方式不變,跑費用流看是否滿流即可。。
這個其實可以看成inf個流,一些可以經過區間流過,接在費用為0的流上,然後形成inf個完整區間,然後比inf少的流由於缺了對應的流,必須從區間流過來補充,因此滿足了下界的要求。。。
/** * ┏┓ ┏┓ * ┏┛┗━━━━━━━┛┗━━━┓ * ┃ ┃ * ┃ ━ ┃ * ┃ > < ┃ * ┃ ┃ * ┃... ⌒ ... ┃ * ┃ ┃ * ┗━┓ ┏━┛ * ┃ ┃ Code is far away from bug with the animal protecting * ┃ ┃ 神獸保佑,程式碼無bug * ┃ ┃ * ┃ ┃ * ┃ ┃ * ┃ ┃ * ┃ ┗━━━┓ * ┃ ┣┓ * ┃ ┏┛ * ┗┓┓┏━┳┓┏┛ * ┃┫┫ ┃┫┫ * ┗┻┛ ┗┻┛ */ #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<queue> #include<cmath> #include<map> #include<stack> #include<set> #include<bitset> #include<stdlib.h> #include<assert.h> #define inc(i,l,r) for(int i=l;i<=r;i++) #define dec(i,l,r) for(int i=l;i>=r;i--) #define link(x) for(edge *j=h[x];j;j=j->next) #define mem(a) memset(a,0,sizeof(a)) #define ll long long #define eps 1e-8 #define succ(x) (1<<x) #define lowbit(x) (x&(-x)) #define sqr(x) ((x)*(x)) #define mid (x+y>>1) #define NM 1005 #define nm 50005 #define pi 3.1415926535897931 const ll inf=1e16; using namespace std; ll read(){ ll x=0,f=1;char ch=getchar() ; while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return f*x; } struct edge{int t;ll v,w;edge*next,*rev;}e[nm],*h[NM],*o=e,*p[NM]; void _add(int x,int y,int w,int v){o->t=y;o->v=v;o->w=w;o->next=h[x];h[x]=o++;} void add(int x,int y,int w,int v){_add(x,y,w,v);_add(y,x,0,-v);h[x]->rev=h[y];h[y]->rev=h[x];} int n,m,_x,_y,_t,s,a[NM]; ll d[NM],ans,w[NM]; bool v[NM]; queue<int>q; ll spfa(){ inc(i,1,n)d[i]=inf;mem(v);mem(w); v[0]++;q.push(0);d[0]=0;w[0]=inf; while(!q.empty()){ int t=q.front();q.pop();v[t]=false; link(t)if(j->w&&d[j->t]>d[t]+j->v){ d[j->t]=d[t]+j->v;w[j->t]=min(w[t],j->w);p[j->t]=j; if(!v[j->t])v[j->t]++,q.push(j->t); } } return w[n]; } int main(){ n=read();m=read(); inc(i,1,n)a[i]=read(); s=10000000; inc(i,1,n)if(a[i]<s)add(i,i+1,s-a[i],0); add(0,1,s,0); while(m--){ _x=read();_y=read();_t=read(); add(_x,_y+1,s,_t); } n++; while(spfa()){ ans+=d[n]*w[n];s-=w[n]; for(int x=n;p[x];x=p[x]->rev->t)p[x]->w-=w[n],p[x]->rev->w+=w[n]; } if(s)return 0*printf("-1\n"); return 0*printf("%lld\n",ans); }
1061: [Noi2008]志願者招募
Time Limit: 20 Sec Memory Limit: 162 MB Submit: 5877 Solved: 3538 [Submit][Status][Discuss]
Description
申奧成功後,布布經過不懈努力,終於成為奧組委下屬公司人力資源部門的主管。布布剛上任就遇到了一個難
題:為即將啟動的奧運新專案招募一批短期志願者。經過估算,這個專案需要N 天才能完成,其中第i 天至少需要
Ai 個人。 布布通過了解得知,一共有M 類志願者可以招募。其中第i 類可以從第Si 天工作到第Ti 天,招募費用
是每人Ci 元。新官上任三把火,為了出色地完成自己的工作,布布希望用盡量少的費用招募足夠的志願者,但這
並不是他的特長!於是布布找到了你,希望你幫他設計一種最優的招募方案。
Input
第一行包含兩個整數N, M,表示完成專案的天數和可以招募的志願者的種類。 接下來的一行中包含N 個非負
整數,表示每天至少需要的志願者人數。 接下來的M 行中每行包含三個整數Si, Ti, Ci,含義如上文所述。為了
方便起見,我們可以認為每類志願者的數量都是無限多的。
Output
僅包含一個整數,表示你所設計的最優方案的總費用。
Sample Input
3 3 2 3 4 1 2 2 2 3 5 3 3 2
Sample Output
14
HINT
1 ≤ N ≤ 1000,1 ≤ M ≤ 10000,題目中其他所涉及的資料均 不超過2^31-1。