题意
将(m)条边添加进一个二分图中,若第(i)个点度数为(c_i),则其代价为(p_{i,c_i}),不保证(p_i)非降,整个图的代价为所有(2n)个点的代价之和,给定(l,r),请求出最大匹配在([l,r])之间时的最小代价
(n,mleq 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
",res);
return 0;
}