1. 程式人生 > 其它 >網路流必刷題

網路流必刷題

未完待續……
serve as網路流做題記錄集&總結

1.CF1146G Zoning Restrictions

https://www.luogu.com.cn/problem/CF1146G

可能思路

  1. 轉化為一個代價決策問題
    即,考慮先把所有房子都建到h,然後再來決策是交罰金還是拆樓
  2. 有可能這類決策問題多采用↓的方法
  • 憑空建立一條邊(u,v)=+∞(本文中除非特殊說明(u,v)都從u到v)
  • 選擇元素i的代價為從源點到i建立一條邊的權值

本題解法

那麼首先是基於一個貪心思想:如果我們要交罰款,那肯定要建滿房子。
於是就可以

  1. 對於每個房子,建立1~h這些點,表示一開始是建了這麼高的
  2. 對每個決策建一個點,把[l,r]這一段的房子的[x+1~h]的點全部向這個點連權值為+∞的邊
  3. 讓這個點跟匯點連條權值為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;
}