TopCoder SRM 348 Div1 Medium RailwayTickets
問題
座席がn個ある電車がある。
m人の乗客がいて、それぞれはa[i]から乗りb[i]の駅で降りる。
電車には同時にn人以上が乗ることはできない。
(乗る駅および降りる駅では数に数えない)
乗客は、乗りたい区間全部に乗れないときは、電車に乗らない。
乗客を選び、最大で何人の乗客を乗せることができるか、求めよ。
制約条件
n≦1000
a[i],b[i]≦10000
乗客の最大数は500くらい?
方針
蟻本220pの問題Intervalsと全く同じ。
区間(a,b)に乗りたい客がいるとき、aからbに容量1,コスト-1の辺を張る。
(i,i+1)に容量∞、コスト0の辺を張る。
このときの最小費用流が、乗せられる客の最大数となる。
ソースコード
const int MAX_V=500; typedef pair<int,int> P; struct edge{ int to,cap,cost,rev; }; int V; vector<edge> G[MAX_V]; int h[MAX_V],dist[MAX_V],prevv[MAX_V],preve[MAX_V]; void add_edge(int from,int to,int cap,int cost){ G[from].pb((edge){to,cap,cost,G[to].size()}); G[to].pb((edge){from,0,-cost,G[from].size()-1}); } int min_cost_flow(int s,int t,int f){ int res=0; fill(h,h+V,0); while(f>0){ priority_queue<P,vector<P>,greater<P> > q; fill(dist,dist+V,inf); dist[s]=0; q.push(P(0,s)); while(!q.empty()){ P p=q.top(); q.pop(); int v=p.second; if(dist[v]<p.first)continue; rep(i,G[v].size()){ edge &e=G[v][i]; if(e.cap>0&&dist[e.to]>dist[v]+e.cost+h[v]-h[e.to]){ dist[e.to]=dist[v]+e.cost+h[v]-h[e.to]; prevv[e.to]=v; preve[e.to]=i; q.push(P(dist[e.to],e.to)); } } } if(dist[t]==inf)return -1; rep(v,V)h[v]+=dist[v]; int d=f; for(int v=t;v!=s;v=prevv[v])d=min(d,G[prevv[v]][preve[v]].cap); f-=d; res+=d*h[t]; for(int v=t;v!=s;v=prevv[v]){ edge &e=G[prevv[v]][preve[v]]; e.cap-=d; G[v][e.rev].cap+=d; } } return res; } class RailwayTickets { public: int minRejects(vector <string> travel, int seats) { vi a,b; rep(i,MAX_V)G[i].clear(); string s; rep(i,travel.size())s+=travel[i]+" "; rep(i,s.size())if(s[i]=='-')s[i]=' '; stringstream ss(s); int p,q; map<int,int> m; while(ss>>p>>q){ a.pb(p), b.pb(q); m[p]=m[q]=0; } p=0; fr(i,m)i->second=p++; //一応座標圧縮しておく。 int n=a.size(); rep(i,n)a[i]=m[a[i]], b[i]=m[b[i]]; V=p+2; int ans=0; add_edge(V-2,0,seats,0); add_edge(p-1,V-1,seats,0); rep(i,p-1)add_edge(i,i+1,inf,0); rep(i,n){ add_edge(b[i],a[i],1,1); add_edge(V-2,b[i],1,0); add_edge(a[i],V-1,1,0); } return min_cost_flow(V-2,V-1,seats+n); } };