標籤:資料 網路流最大流 dfs bfs
題目:hdoj 2883 kebab
題意:現在有n個人要烤肉,有m個烤肉架,然後給出每個人的烤肉開始時間si,結束時間ei,以及要烤肉的串數num,還有拷一串的時間ti,然後問你能不能滿足所有人的要求。
分析:這是一個比較經典的最大流,經典在於建圖方法,這個題目痛點在於時間跨度在0---100 0000,如果時間短的話就可以用題目3572的做法了。點擊開啟連結
後面看了別人的建圖方法,確實比較經典,經典在於把區間縮點了,這個題目的痛點在於時間跨度大,那麼我們可以把所有的時間點記錄下來,然後排序,然後以這些時間點建圖。
建圖方案:
首先超級源點s到每個人 i 建容量為 num * ti 邊,
然後對於每個人的烤肉時間區間,枚舉排序之後的所有的相鄰時間點,相鄰兩點也組成一個區間,那麼假如枚舉的區間包含在這個人的時間區間內,從人 i 建邊 區間 j,容量inf
然後每個區間開始點 j 建邊到超級匯點建邊容量為(time【j+1】-time【j】)*m。
這樣,如果最大流為所有的count(num * ti),則滿足要求。
範例1建圖之後得到這樣的圖:
這個題目也是用c++提交的,G++編譯錯誤,不解。
AC代碼:
#include <cstdio>#include <cstring>#include <iostream>#include <string>#include <algorithm>#include <vector>#include <queue>using namespace std;#define Del(a,b) memset(a,b,sizeof(a))const int N = 1020;const int inf = 0x3f3f3f3f;int n,m;int Min(int a,int b){return a>b?b:a;}struct Node{ int from,to,cap,flow;};vector<int> v[N];vector<Node> e;int vis[N]; //構建層次圖int cur[N];void add_Node(int from,int to,int cap){Node tmp1,tmp2;tmp1.cap=from=from,tmp1.to=to,tmp1.cap=cap,tmp1.flow=0; e.push_back(tmp1);tmp2.from=to,tmp2.to=from,tmp2.cap=0,tmp2.flow=0; e.push_back(tmp2); int tmp=e.size(); v[from].push_back(tmp-2); v[to].push_back(tmp-1);}bool bfs(int s,int t){ Del(vis,-1); queue<int> q; q.push(s); vis[s] = 0; while(!q.empty()) { int x=q.front(); q.pop(); for(int i=0;i<v[x].size();i++) { Node tmp = e[v[x][i]]; if(vis[tmp.to]<0 && tmp.cap>tmp.flow) //第二個條件保證 { vis[tmp.to]=vis[x]+1; q.push(tmp.to); } } } if(vis[t]>0) return true; return false;}int dfs(int o,int f,int t){ if(o==t || f==0) //最佳化 return f; int a = 0,ans=0; for(int &i=cur[o];i<v[o].size();i++) //注意前面 ’&‘,很重要的最佳化 { Node &tmp = e[v[o][i]]; if(vis[tmp.to]==(vis[o]+1) && (a = dfs(tmp.to,Min(f,tmp.cap-tmp.flow),t))>0) { tmp.flow+=a; e[v[o][i]^1].flow-=a; //存圖方式 ans+=a; f-=a; if(f==0) //注意最佳化 break; } } return ans; //最佳化}int dinci(int s,int t){ int ans=0; while(bfs(s,t)) { Del(cur,0); int tm=dfs(s,inf,t); ans+=tm; } return ans;}struct Node1{ int si,num,ei,ti;};Node1 a[250];vector<int> time;int main(){ //freopen("Input.txt","r",stdin); int n,m; while(~scanf("%d%d",&n,&m)) { int s=0,t=3*n+2,count=0,i,j; for(i=1;i<=n;i++) { scanf("%d%d%d%d",&a[i].si,&a[i].num,&a[i].ei,&a[i].ti); time.push_back(a[i].si); time.push_back(a[i].ei); int tmp = a[i].num*a[i].ti; count+=tmp; add_Node(s,i,tmp); } sort(time.begin(),time.end()); for(i=1;i<=n;i++) { for(j=0;j<(time.size()-1);j++) { if(a[i].si<=time[j] && a[i].ei>=time[j+1]){ add_Node(i,n+j+1,inf); //printf("-%d ",time[j]); } } } for(i=0;i<(time.size()-1);i++) add_Node(n+i+1,t,(time[i+1]-time[i])*m); int ans=dinci(s,t); //printf("%d\n",ans); if(ans==count) printf("Yes\n"); else printf("No\n"); for(i=0;i<=t;i++) v[i].clear(); e.clear();time.clear(); } return 0;}
hdoj 2883 kebab 【經典最大流】