P9902 『PG2』模拟最大流 题解

首先最大流等于最小割,然后就能很容易地想到一个状压 dp 做法:记 \(f_{i,s}\) 表示使得前 \(i\) 个点中,最后 \(k\) 个点与点 \(1\) 的联通情况为 \(s\) 的最小代价。然后考虑下一个点是否联通直接转移即可,然后就做完了。时间复杂度 \(\mathcal O(n2^k)\)

参考代码:

#include<bits/stdc++.h>
#define mxn 80003
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define rept(i,a,b) for(int i=a;i<b;++i)
using namespace std;
int n,m,k,s,d[mxn][10],f[mxn][128];
signed main(){
	scanf("%d%d%d",&n,&m,&k);
	for(int i=0,x,y,z;i<m;++i){
		scanf("%d%d%d",&x,&y,&z);
		d[y][y-x]+=z;
	}
	s=(1<<k)-1;
	memset(f,0x3f,sizeof(f));
	f[1][1]=0;
	rept(i,1,n){
		rept(j,0,1<<k)if(f[i][j]<1e9){
			int sm=0;
			rept(x,0,k)if((j>>x)&1)sm+=d[i+1][x+1]; 
			f[i+1][(j<<1)&s]=min(f[i+1][(j<<1)&s],f[i][j]+sm);
			f[i+1][(j<<1|1)&s]=min(f[i+1][(j<<1|1)&s],f[i][j]);
		}
	}
	int ans=1e9;
	rept(i,0,1<<k)if(!(i&1))ans=min(ans,f[n][i]);
	cout<<ans;
	return 0;
}
posted @ 2024-04-05 20:45  zifanwang  阅读(25)  评论(0)    收藏  举报