網路流必刷題
阿新 • • 發佈:2022-01-10
未完待續……
serve as網路流做題記錄集&總結
1.CF1146G Zoning Restrictions
https://www.luogu.com.cn/problem/CF1146G
可能思路
- 轉化為一個代價決策問題
即,考慮先把所有房子都建到h,然後再來決策是交罰金還是拆樓 - 有可能這類決策問題多采用↓的方法
- 憑空建立一條邊(u,v)=+∞(本文中除非特殊說明(u,v)都從u到v)
- 選擇元素i的代價為從源點到i建立一條邊的權值
本題解法
那麼首先是基於一個貪心思想:如果我們要交罰款,那肯定要建滿房子。
於是就可以
- 對於每個房子,建立1~h這些點,表示一開始是建了這麼高的
- 對每個決策建一個點,把[l,r]這一段的房子的[x+1~h]的點全部向這個點連權值為+∞的邊
- 讓這個點跟匯點連條權值為c的邊
圖解:(不要看白色線,畫錯了)
所以答案就是h*h*n-最小割。
點選檢視程式碼
#include <bits/stdc++.h> using namespace std; const int N=2555,M=260000; //邊要數清楚 int n,h,m,tot=1,dis[N],we[M]; vector<pair<int,int> >G[N]; queue<int>Q; bool bfs(){ memset(dis,0,sizeof(dis)); Q.push(1),dis[1]=1; while(!Q.empty()){ int x=Q.front();Q.pop(); for(int i=0;i<G[x].size();i++){ int y=G[x][i].first,z=G[x][i].second; if(we[z]&&!dis[y])dis[y]=dis[x]+1,Q.push(y); } } return dis[2]; } int dfs(int x,int in){ if(x==2)return in; int out=0; for(int i=0;i<G[x].size();i++){ int y=G[x][i].first,z=G[x][i].second; if(we[z]&&dis[y]==dis[x]+1){ int los=dfs(y,min(in,we[z])); we[z]-=los,we[z^1]+=los,in-=los,out+=los; } } if(!out)dis[x]=-1; return out; } void ade(int u,int v,int w){ G[u].push_back(make_pair(v,++tot)),we[tot]=w; G[v].push_back(make_pair(u,++tot)),we[tot]=0; } int main(){ cin>>n>>h>>m; for(int i=1;i<=n;i++)for(int j=1;j<=h;j++)ade(1,2+(i-1)*h+j,2*j-1); for(int i=1,l,r,x,c;i<=m;i++){ cin>>l>>r>>x>>c; ade(2+n*h+i,2,c); for(int j=l;j<=r;j++)for(int k=x+1;k<=h;k++)ade(2+(j-1)*h+k,2+n*h+i,1e9); } int ans=0; while(bfs())ans+=dfs(1,1e9); cout<<h*h*n-ans; }