1. 程式人生 > >POJ.1752.Advertisement(差分約束 最長路SPFA)

POJ.1752.Advertisement(差分約束 最長路SPFA)

pos 分享 inf Go problem 技術 pty const jks

題目鏈接

\(Description\)

有n個人在一條直線上跑步,每個人的起點 \(Si\)、終點 \(Ei\) 已知;每個點可以放一個廣告牌,一個人i能看到的廣告牌數量為 \(Ei-Si+1\)
要求使每個人看到的廣告牌數量不小於 \(k\) (若 \(Ei-Si+1<k\) 則應看到 \(Ei-Si+1\))。輸出最少需要多少廣告牌及方案。

(這翻譯2333)
技術分享圖片

\(Solution\)

\(Sum_i\) 表示在 \([1,i]\) 廣告牌總數,那麽由題意有 \(Sum_{Ei}-Sum_{Si-1}>=k\),這是對於 \(Ei-Si+1>=k\)
\(C=Ei-Si+1\)

,若C<k,則 \(Sum_{Ei}-Sum_{Si-1}=C\),拆成兩個式子
同時每個位置的限制 \(0<=Sum_i-Sum{i-1}<=1\)
\(Sum_i\) 為點建邊,求 \(Sum_0\) -> \(Sum_n\) 的最長路即為最少需要數量
輸出方案: 若i處建了廣告牌,則有 \(dis_i-dis_{i-1}=1\)

註意,Dijkstra不能用來求最長路

//1240K 735MS
#include <queue>
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar() #define mp std::make_pair #define pr std::pair<int,int> const int N=10005,M=60005,INF=0x3f3f3f3f; int n,K,Enum,H[N<<1],nxt[M],to[M],val[M],dis[N<<1]; bool vis[N<<1]; //std::priority_queue<pr> q; std::queue<int> que; inline int read() { int now=0
,f=1;register char c=gc(); for(;!isdigit(c);c=gc()) if(c=='-') f=-1; for(;isdigit(c);now=now*10+c-'0',c=gc()); return now*f; } inline void AddEdge(int u,int v,int w){ to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum, val[Enum]=w; } //int Dijkstra(int mn,int mx) //{ // for(int i=mn+1; i<=mx; ++i) dis[i]=-INF; // q.push(mp(0,mn)); // while(!q.empty()) // { // int x=q.top().second;q.pop(); // if(vis[x]) continue; // vis[x]=1; // for(int i=H[x]; i; i=nxt[i]) // if(dis[to[i]]<dis[x]+val[i]) // { // dis[to[i]]=dis[x]+val[i]; // if(!vis[to[i]]) q.push(mp(dis[to[i]],to[i])); // } // } // return dis[mx]; //} int SPFA(int mn,int mx) { for(int i=mn+1; i<=mx; ++i) dis[i]=-INF; que.push(mn); while(!que.empty()) { int x=que.front();que.pop(); vis[x]=0; for(int i=H[x]; i; i=nxt[i]) if(dis[to[i]]<dis[x]+val[i]) { dis[to[i]]=dis[x]+val[i]; if(!vis[to[i]]) que.push(to[i]),vis[to[i]]=1; } } return dis[mx]; } int main() { K=read(),n=read(); int mx=0,mn=N<<1; for(int st,ed,t,i=1; i<=n; ++i) { st=read()+N, ed=read()+N; if(st>ed) std::swap(st,ed); mn=std::min(mn,--st), mx=std::max(mx,ed); if((t=ed-st)<K) AddEdge(st,ed,t),AddEdge(ed,st,-t); else AddEdge(st,ed,K); } mn-=2; for(int i=mn; i<=mx; ++i) AddEdge(i-1,i,0),AddEdge(i,i-1,-1); printf("%d\n",SPFA(mn,mx)); for(int i=mn; i<=mx; ++i) if(dis[i]==dis[i-1]+1) printf("%d\n",i-N); return 0; }

POJ.1752.Advertisement(差分約束 最長路SPFA)