題意是說給出一些閉區間,這些區間上整點可以選擇放一個元素或者不放,但是每個區間都有一個下限,就是說你在這個區間裡面的元素個數不能低於這個下限值。
最後要求出最少需要幾個元素才能滿足每個區間的要求。
建圖(參見這裡)之後可以轉化成最長路問題。
另:差分約束中dist[ ]的初始化很有意思,比如你初始化的是 0 ,那麼按照最長路更新dist[ ]數組,最後得到的就是大於 0 的最小值;如果按照最短路更新dist[ ]的話,最後結果是小於 0 的最大值。 ——LC
還有,針對這種差分約束問題建圖轉化成為最短路問題的處理,很多 blog 的建圖都是為了隊列入隊操作時方便,加入了一個虛點,這個虛點和圖中每一個點都連一條權值為 0 的邊,開始尋找最長路時,首先把這個虛點入隊。其實我們可以省略這個點,這樣的話,我們需要手動把圖中每個點入隊,同時把他們的dist[ ]值更新成 0 ,聽著有點麻煩是吧,不過的確是個省時間的辦法,至於最佳化效果怎麼樣,就不好說了。 ——LC
My Code:
#include<iostream>#include<queue>#include<cstdio>#include<cstring>#include<climits>#define find_min(a,b) a<b?a:b#define find_max(a,b) a>b?a:busing namespace std;const int N = 50010;struct Edge{int s,e,v;int next;}edge[N];int n,e_num,p_num,vis[N],head[N],dist[N];int left_x,right_x;void AddEdge(int a,int b,int c){edge[e_num].s=a; edge[e_num].e=b; edge[e_num].v=c;edge[e_num].next=head[a]; head[a]=e_num++;}queue <int>q;void spfa(){while(!q.empty()){int cur=q.front();q.pop();vis[cur]=0;for(int i=head[cur];i!=-1;i=edge[i].next){int u=edge[i].e;if(dist[u] < dist[cur]+edge[i].v){dist[u]=dist[cur]+edge[i].v;if(!vis[u]){q.push(u);vis[u]=1;}}}if(cur>left_x && dist[cur]-1 > dist[cur-1]){dist[cur-1]=dist[cur]-1;if(!vis[cur-1]){q.push(cur-1);vis[cur-1]=1;}}if(cur<right_x && dist[cur] > dist[cur+1]){dist[cur+1]=dist[cur];if(!vis[cur+1]){q.push(cur+1);vis[cur+1]=1;}}}printf("%d\n",dist[right_x]);}void getmap(){int i,a,b,c;e_num=p_num=1;memset(head,-1,sizeof(head));memset(vis,0,sizeof(vis));left_x=INT_MAX; right_x=INT_MIN;for(i=1;i<=n;i++){scanf("%d%d%d",&a,&b,&c);AddEdge(a,b+1,c);//可能存在a==b的情況left_x=find_min(left_x,a);right_x=find_max(right_x,b+1);}//省略掉那個虛點,可以最佳化spfa.虛點作用是讓所有點入隊,且dist[]更新為0,//所以省略掉這點的話,需要手動把所有點入隊,dist[]賦初值為0memset(dist,0,sizeof(dist));for(i=left_x;i<=right_x;i++){q.push(i);vis[i]=1;}}int main(){while(~scanf("%d",&n)){getmap();spfa();}return 0;}