nanchang B A Funny Bipartite Graph

题意是:给你一个二分图,让你在其中选一些边,边和边两边的点构成一个新图,然后问新图的最小代价?
新图要满足两个条件:右边的点必须全选,左边的点必须满足互斥关系。

原图也满足一些性质,每个点的度小于3,左边的每个点不会向左边编号比它小的点连边。

为什么爆搜能过,为什么爆搜能过,为什么爆搜能过。。。。。。

而且还比我快。

爆搜就是加个剪枝,如果当前的sum比ans大就不继续往下搜了。。。。不会证复杂度。

然后我写的大概是一个折半dp预处理的做法,慢了十倍左右

就是首先不加剪枝的爆搜一定会tle嘛,然后就考虑折半的复杂度,因为他保证每个点不会连向比它小的点,然后我们爆搜左边前一半的点,这样右边前一半的点一定会都被选到,然后dp记录所有的状态,dp[sl][sr]表示左边上一半状态为sl的时候,右边下半部分为加入了sr的时候最小花费。

因为每个点最多向右连3条边,一共27条边嘛,然后又有右边每个点最多连一条边(显然),右边前一半的点一定会被选到的限制,爆搜复杂度肯定是ok的嘛,具体没算。

然后爆搜左边下半部分的点,这样确定的右边的状态是这次的状态 sr^(1<<(n)-1)^(1<<(n/2)-1),就是所有点减去这次搜的点。然后确定左边的状态,考虑这次的转态sl会有一个互斥的状态ban,那么合法的状态就是 ~ban的子集。

只有把第一次的dp再子集dp一下,就可以o(1)得到了。这个高位前缀和直接子集dp复杂度都是可以的,分别是2^n*(n/2)和2^(n/2)*3^(n/2)的。

附一下代码:

#include <bits/stdc++.h>

using namespace std;

#define N 100005
#define M 22
#define ll long long
#define mod 1000000007
#define go(i,a,b) for(int i=(a);i<=(b);i++)
#define dep(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
#define inf 0x3f3f3f3f
#define ld long double
#define pii pair<int,int>
#define fi first
#define se second
#define vi vector<int>
#define madd(a,b) (a+=(b)%mod)%=mod
#define lowb(c,len,x) lower_bound(c+1,c+len+1,x)-c
#define uppb(c,len,x) upper_bound(c+1,c+len+1,x)-c
#define ls i*2+1
#define rs i*2+2
#define mid (l+r)/2
#define root 1,n,0
#define lson l,mid,ls
#define rson mid+1,r,rs
#define l(x) (x&-x)
#define b(x) (1<<(x))
#define ms(a,b) memset(a,b,sizeof a)
#define muti int T;cin>>T;while(T--)
#define Min(a,b) (a=min(a,b))
int n,num[1<<19],ban[N],trans[N];
ll v[N][6];
char ss[N];
ll dp[1<<10][1<<10],ans;
void dfs(int k,int sl,int sr,ll sum){

    if(k==n){
        Min(dp[sl][sr>>(n/2)],sum);
        //Min(ans,sum);
        return ;

    }
    if(sr&b(k))dfs(k+1,sl,sr,sum);

    if(sl&ban[k])return ;

    for(int s=trans[k];s;s=(s-1)&trans[k]){
        if(sr&s)continue;
        //if(sum+v[k][num[s]]>ans)continue;
        if((sr^s)&b(k))dfs(k+1,sl^b(k),sr^s,sum+v[k][num[s]]);
    }
}
void dfs1(int k,int slban,int sr,ll sum){
    if(k==n){
        int s=(b(n/2)-1)&(~slban),t=((b(n)-1)^sr)>>(n/2);
        Min(ans,(sum+dp[s][t]));
        return ;
    }
    dfs1(k+1,slban,sr,sum);
    if(slban&b(k))return ;
    for(int s=trans[k];s;s=(s-1)&trans[k]){
        if(sr&s)continue;
        dfs1(k+1,slban|ban[k],sr|s,sum+v[k][num[s]]);
    }
}
int main()
{

    go(i,1,b(19)-1)num[i]=num[i>>1]+(i&1);
    muti{
        scanf("%d",&n);
        ms(dp,inf);ans=inf;
        go(i,0,n-1){
            scanf("%s",ss);
            trans[i]=0;
            go(j,0,n-1)if(ss[j]=='1')trans[i]|=b(j);
        }
        go(i,0,n-1){
            scanf("%s",ss);
            ban[i]=0;
            go(j,0,n-1)if(ss[j]=='1')ban[i]|=b(j);
        }
        go(i,0,n-1)scanf("%d",&v[i][1]),v[i][2]=v[i][1]*v[i][1],v[i][3]=v[i][1]*v[i][2];
        dfs(0,0,0,0);
        go(i,0,b(n/2+1)-1)go(k,0,n/2-1)go(j,1,b(n/2)-1)if(j&b(k))Min(dp[j][i],dp[j^b(k)][i]);

        dfs1(n/2,0,0,0);
        if(ans>=inf)ans=-1;
        cout<<ans<<endl;
    }
}

然后爆搜的代码,其实很像。

#include <bits/stdc++.h>

using namespace std;

#define N 100005
#define M 22
#define ll long long
#define mod 1000000007
#define go(i,a,b) for(int i=(a);i<=(b);i++)
#define dep(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
#define inf 0x3f3f3f3f
#define ld long double
#define pii pair<int,int>
#define fi first
#define se second
#define vi vector<int>
#define madd(a,b) (a+=(b)%mod)%=mod
#define lowb(c,len,x) lower_bound(c+1,c+len+1,x)-c
#define uppb(c,len,x) upper_bound(c+1,c+len+1,x)-c
#define ls i*2+1
#define rs i*2+2
#define mid (l+r)/2
#define root 1,n,0
#define lson l,mid,ls
#define rson mid+1,r,rs
#define l(x) (x&-x)
#define b(x) (1<<(x))
#define ms(a,b) memset(a,b,sizeof a)
#define muti int T;cin>>T;while(T--)
#define Min(a,b) (a=min(a,b))
int n,num[1<<19],ban[N],trans[N];
ll v[N][6];
char ss[N];
ll dp[1<<10][1<<10],ans;
void dfs(int k,int sl,int sr,ll sum){

    if(k==n){
        //Min(dp[sl][sr>>(n/2)],sum);
        Min(ans,sum);
        return ;

    }
    if(sr&b(k))dfs(k+1,sl,sr,sum);

    if(sl&ban[k])return ;

    for(int s=trans[k];s;s=(s-1)&trans[k]){
        if(sr&s)continue;
        if(sum+v[k][num[s]]>ans)continue;
        if((sr^s)&b(k))dfs(k+1,sl^b(k),sr^s,sum+v[k][num[s]]);
    }
}

int main()
{

    go(i,1,b(19)-1)num[i]=num[i>>1]+(i&1);
    muti{
        scanf("%d",&n);
        ms(dp,inf);ans=inf;
        go(i,0,n-1){
            scanf("%s",ss);
            trans[i]=0;
            go(j,0,n-1)if(ss[j]=='1')trans[i]|=b(j);
        }
        go(i,0,n-1){
            scanf("%s",ss);
            ban[i]=0;
            go(j,0,n-1)if(ss[j]=='1')ban[i]|=b(j);
        }
        go(i,0,n-1)scanf("%d",&v[i][1]),v[i][2]=v[i][1]*v[i][1],v[i][3]=v[i][1]*v[i][2];
        dfs(0,0,0,0);

        if(ans>=inf)ans=-1;
        cout<<ans<<endl;
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章