1. 程式人生 > 其它 >Codeforces 1373F - Network Coverage(模擬網路流)

Codeforces 1373F - Network Coverage(模擬網路流)

模擬網路流+dp,套路題

Codeforces 題面傳送門 & 洛谷題面傳送門

提供一個模擬網路流的題解。

首先我們覺得這題一臉可以流的樣子,稍微想想可以想到如下建圖模型:

  • 建立源點 \(S,T\) 和上下兩排點,不妨設上排點為 \(x_1,x_2,\cdots,x_n\),下排點為 \(y_1,y_2,\cdots,y_n\)
  • 對於每個 \(i\) 我們連一條 \(S\to x_i\),容量為 \(b_i\) 的邊,表示每個基站最多提供 \(b_i\) 個網路服務。
  • 對於每個 \(i\),我們連邊 \(x_i\to y_i,x_i\to y_{i\bmod n+1}\),權值均為 \(\infty\),表示基站 \(i\)
    可以為家庭 \(i\) 和家庭 \(i\bmod n+1\) 提供網路服務。
  • 連邊 \(y_i\to T\),權值 \(a_i\),表示家庭 \(i\) 需要 \(a_i\) 個網路服務。

然後跑最大流看看最大流是否等於 \(\sum\limits_{i=1}^na_i\) 即可。

由於此題 \(n\) 高達 \(10^6\),因此直接跑最大流顯然是不可取的。因此考慮模擬網路流,也就是用最小割解決最大流的思路。注意到圖是一個環形結構,直接做可能會出現後效性有關的問題,因此我們不妨先解決鏈的情況,即,假設 \(x_n\to y_1\) 的邊不存在。設 \(dp_{i,j}(j\in\{0,1\})\)

表示現在只考慮 \(x_1,x_2,\cdots,x_i,y_1,y_2,\cdots,y_i,S,T\) 的匯出子圖,\(S,T\) 在匯出子圖中不連通且 \(S\to x_i\) 的邊的狀態為 \(j\)\(0\):連上,\(1\):斷開)的最小代價,那麼有 \(dp_{i,j}=\min\limits_{k\in\{0,1\}}dp_{i-1,k}+kb_i+[j=0\lor k=0]·a_i\),邊界條件 \(dp_{0,0}=0\)

接下來考慮環的情況,其實感覺會了鏈的情況,環的情況就異常 trivial 了。按照套路列舉 \(S\to x_n\) 的邊連上還是斷開,設為 \(c\),那麼與鏈的情況不同之處在於,邊界條件變為 \(dp_{0,c}=0\)

,因為 \(S\to x_n\) 的邊連上等價於 \(x_n\to y_1\) 的邊沒有被斷開,最後用 \(dp_{n,c}\) 更新答案即可。

時間複雜度線性。

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
#define mt make_tuple
#define eprintf(...) fprintf(stderr,__VA_ARGS__)
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef long double ld;
namespace fastio{
	#define FILE_SIZE 1<<23
	char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
	inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
	inline void putc(char x){(*p3++=x);}
	template<typename T> void read(T &x){
		x=0;char c=getchar();T neg=0;
		while(!isdigit(c)) neg|=(c=='-'),c=getchar();
		while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
		if(neg) x=-x;
	}
	template<typename T> void recursive_print(T x){
		if(!x) return;
		recursive_print(x/10);putc(x%10+'0');
	}
	template<typename T> void print(T x){
		if(!x) putc('0');if(x<0) putc('-'),x=-x;
		recursive_print(x);
	}
	template<typename T> void print(T x,char c){print(x);putc(c);}
	void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
}
template<typename Tv,int limN,int limM> struct link_list{
	int hd[limN+5],nxt[limM+5],item_n=0;Tv val[limM+5];
	void clear(){memset(hd,0,sizeof(hd));item_n=0;}//be aware of the TC of memset
	void ins(int x,Tv y){val[++item_n]=y;nxt[item_n]=hd[x];hd[x]=item_n;}
};
using namespace fastio;
const int MAXN=1e6;
const ll INF=0x3f3f3f3f3f3f3f3fll;
int n,a[MAXN+5],b[MAXN+5];ll dp[MAXN+5][2];
void solve(){
	read(n);ll sum=0,res=INF;
	for(int i=1;i<=n;i++) read(a[i]),sum+=a[i];
	for(int i=1;i<=n;i++) read(b[i]);
	for(int _=0;_<2;_++){
		for(int i=0;i<=n;i++) dp[i][0]=dp[i][1]=INF;
		dp[0][_]=0;
		for(int i=1;i<=n;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++)
			chkmin(dp[i][j],dp[i-1][k]+j*b[i]+(!(j&k))*a[i]);
		chkmin(res,dp[n][_]);
	} //printf("%lld\n",res);
	printf("%s\n",(res==sum)?"YES":"NO");
}
int main(){int qu;read(qu);while(qu--) solve();return 0;}