模拟网络流之dp类:1107T3

http://cplusoj.com/d/senior/p/SS231107C

可以发现是求第 i i i 层到第 j j j 层的最大流。

同样先转成最小割,显然割点比个边优。然后我们可以利用状压dp来求。

f ( i , j , s ) f(i,j,s) f(i,j,s) 表示在第 i i i 层,还可以割 j j j 条边,这层还存活的点集为 s s s,最快在哪里就流不动了。

我们先假设一条不割从上一层转移。然后我们枚举割哪条从同层转移。

#include
using namespace std;
#ifdef LOCAL
 #define debug(...) fprintf(stdout, ##__VA_ARGS__)
#else
 #define debug(...) void(0)
#endif
#define int long long
inline int read(){int x=0,f=1;char ch=getchar(); while(ch<'0'||
ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define Z(x) (x)*(x)
#define pb push_back
#define fi first
#define se second
//srand(time(0));
#define N 60010
#define M 12
//#define mo
void Mx(int &a, int b) {
	a=max(a, b); 
}
int n, m, i, j, k, T, t;
int ans, x, y, s, ns[N][600]; 
int b[M][M], dp[2][M][600]; 
char str[M]; 

signed main()
{
	freopen("stairs.in", "r", stdin);
	freopen("stairs.out", "w", stdout);
	#ifdef LOCAL
	  freopen("in.txt", "r", stdin);
	  freopen("out.txt", "w", stdout);
	#endif
//	T=read();
//	while(T--) {
//
//	}
	n=read(); m=read(); 
	for(i=1; i<n; ++i) {
		for(x=0; x<m; ++x) {
			scanf("%s", str); 
//			debug("%s\n", str); 
			for(y=0; y<m; ++y) b[x][y]=str[y]-'0'; 
		}
		for(s=0; s<(1<<m); ++s) {
			for(x=0; x<m; ++x) 
				for(y=0; y<m; ++y)
					if(((s>>y)&1) && b[x][y]) {
//						debug("%d %d\n", x, y+m); 
						ns[i+1][s]|=(1<<x); 
					}
//			debug("ns[%d %d]=%d\n", i+1, s, ns[i+1][s]); 
		}
		if(i==1) {
			for(s=0; s<(1<<m); ++s) {
				for(x=0; x<m; ++x) 
					for(y=0; y<m; ++y)
						if(((s>>x)&1) && b[x][y]) {
							ns[i][s]|=(1<<y); 
						}
			}
		}
//		debug("\n"); 
	}
	for(j=0; j<=m; ++j) {
		for(s=1; s<(1<<m); ++s) {
			dp[i&1][j][s]=0; 
//			if(ns[i][s]==0) dp[i&1][j][s]=2; 
		}
		dp[1][j][0]=1; 
	}
	for(i=2; i<=n; ++i) {
		for(j=0; j<=m; ++j) {
			for(s=0; s<(1<<m); ++s) {
				dp[i&1][j][s]=0; 
				if(i==2) {
					for(k=t=0; k<m; ++k) if((ns[i][s]>>k)&1) ++t; 
					if(t==j) dp[i&1][j][s]=1; 
				}
//				if(ns[i][s]==0) dp[i&1][j][s]=i; 
			}
			dp[i&1][j][0]=i; 
		}
		for(j=0; j<=m; ++j)
			for(s=0; s<(1<<m); ++s) 
				Mx(dp[i&1][j][s], dp[(i&1)^1][j][ns[i][s]]); 
		for(j=1; j<=m; ++j) 
			for(s=0; s<(1<<m); ++s) {
				for(k=0; k<m; ++k) if((s>>k)&1)
					Mx(dp[i&1][j][s], dp[i&1][j-1][s-(1<<k)]); 
//				debug("dp[%lld %lld %lld] = %lld\n", i, j, s, dp[i&1][j][s]); 
			}
		for(j=m, s=(1<<m)-1; j>=1; --j) {
			debug("dp[%lld %lld] = %lld \n", i, j, dp[i&1][j][s]) ; 
			ans+=(dp[i&1][j][s]-dp[i&1][j-1][s])*j; 
//			if(dp[i&1][j][s]-dp[i&1][j-1][s] && dp[i&1][j][s]==i) ans-=j; 
		}
		ans-=m; 
		debug("%lld\n", ans); 
	}
		
	printf("%lld", ans); 
	return 0;
}

你可能感兴趣的:(动态规划,模拟网络流)