MEX Foundation Contest B
题意
将\(m\)条边添加进一个二分图中,若第\(i\)个点度数为\(c_i\),则其代价为\(p_{i,c_i}\),不保证\(p_i\)非降,整个图的代价为所有\(2n\)个点的代价之和,给定\(l,r\),请求出最大匹配在\([l,r]\)之间时的最小代价
\(n,m\leq 30\)
题解
夏姬八算
假设现在的图已经没有增广路了,那么此时的匹配个数就是最大匹配的个数,我们要使其在\([l,r]\)之间
由于没有增广路,那么我们从每一条匹配边开始跑,会有三种不同的路径
\(1.\)开头为右边的点,开头为匹配边,结尾为右边的点,结尾为非匹配边
\(2.\)开头为右边的点,开头为匹配边,结尾为左边的点,结尾为匹配边
\(3.\)开头为左边的点,开头为匹配边,结尾为左边的点,结尾为非匹配边
那么每一条匹配边所在的路径一定是上述三种情况之一,所以我们可以把所有的匹配边和非匹配边定向
先来考虑左边的点,右边的点同样计算
设\(f(i,a,b,c,d)\)表示还需要考虑\([i..n]\)的点,此时向左的非匹配边还剩\(a\)条,向右的非匹配边还剩\(b\)条,向右的匹配边还剩\(c\)条,向左的匹配边还剩\(d\)条(注意,向左的非匹配边,它的右边对应的点一定是一个匹配点,否则这里就会产生一条增广路,向右的非匹配边同理)
如果\(c>0\),那么\(i\)可以选择连出一条向右的匹配边,那么会有\([0,a]\)条向左的非匹配边连向它
如果\(d>0\),那么\(i\)可以选择连入一条向左的匹配边,那么会有它可以连出\([0,b]\)条向右的非匹配边
如果不选择连匹配边,那么\(i\)只能选择有\([0,a]\)条向左的非匹配边连向它(此时这里就是\(3\)号路径的结尾)
用记忆化搜索即可
右边的点同理,不过为了防止\(2\)号路径被重复计算,我们强制一条从左边开始的路径只能在左边结束(即\(3\)号路径),一条从右边开始的路径可以任意在左边或右边结束(即\(1,2\)号路径)
时间复杂度\(O(n^6)\)
我觉得可以改一改变成计数题就是了
//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
using namespace std;
typedef long long ll;
const int N=31;const ll inf=1e18;
int p[65][35],n,m,l,r;
ll f[N][N][N][N][N],g[N][N][N][N][N],res;
ll F(int pos,int a,int b,int c,int d){
if(pos==n+1)return !a&&!b&&!c&&!d?0:inf;
R ll &res=f[pos][a][b][c][d];
if(res<=inf)return res;
if(c)fp(i,0,a)cmin(res,F(pos+1,a-i,b,c-1,d)+p[pos][i+1]);
if(d)fp(i,0,b)cmin(res,F(pos+1,a,b-i,c,d-1)+p[pos][i+1]);
fp(i,0,a)cmin(res,F(pos+1,a-i,b,c,d)+p[pos][i]);
return res>=inf?res=inf:res;
}
ll G(int pos,int a,int b,int c,int d){
if(pos==n+1)return !a&&!b&&!c&&!d?0:inf;
R ll &res=g[pos][a][b][c][d];
if(res<=inf)return res;
if(c)fp(i,1,a)fp(j,0,b)cmin(res,G(pos+1,a-i,b-j,c-1,d)+p[pos+n][i+j+1]);
if(d)fp(i,0,b)cmin(res,G(pos+1,a,b-i,c,d-1)+p[pos+n][i+1]);
fp(i,0,b)cmin(res,G(pos+1,a,b-i,c,d)+p[pos+n][i]);
return res>=inf?res=inf:res;
}
int main(){
// freopen("testdata.in","r",stdin);
freopen("matching.in","r",stdin);
freopen("matching.out","w",stdout);
scanf("%d%d%d%d",&n,&m,&l,&r),res=inf;
fp(i,1,n<<1)fp(j,0,m)scanf("%d",&p[i][j]);
memset(f,0x3f,sizeof(f));
memset(g,0x3f,sizeof(g));
fp(c,0,r)fp(d,max(0,l-c),r-c)fp(a,0,m-c-d){
R int b=m-a-c-d;
cmin(res,F(1,a,b,c,d)+G(1,a,b,c,d));
}
printf("%lld\n",res);
return 0;
}