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;
    }
}

 

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