首先最大流等于最小割,然后就能很容易地想到一个状压 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;
}
标签:联通,题解,PG2,P9902,模拟,define
From: https://www.cnblogs.com/zifanoi/p/18116168