zoukankan      html  css  js  c++  java
  • Codeforces 1430G Yet Another DAG Problem 状压dp

    Codeforces 1430G Yet Another DAG Problem

    题意

    (n)个点(m)条边的有向无环图,每条边有边权(w_i),现在让你给每个点一个点权(a_v),对于第(i)条边((x,y)),写上一个数字(b_i=a_x-a_y)并且(a_x>a_y),使得(sum_{i=1}^{m}w_ib_i)最小。

    (nle 18)

    分析

    (sum_{i=1}^{m}w_ib_i)转换为(sum_{i=1}^{n}a_ic_i),其中(c_i)为点(i)连出去的边的边权和减去连向点(i)的边权和。

    考虑将点按点权分层,显然层数不会超过点数,所以点权赋值的范围可以为([0,n-1]),即最多将点分成(n)层,第(i)层的点的点权为(i-1)

    (dp[i][S])为前(i)层的点集为(S)并且(sum_{i in S}a_ic_i)的值最小,这样我们就可以枚举(S)的子集来转移,具体为枚举(S)的一个子集(K),若子集(K)中的点连出去的点都在集合(S oplus K)中,那么子集(K)就可以作为(S)中第(i)层的点集,加上(sum_{j in K}c_j cdot (i-1))转移即可,子集(K)连出去的点的点集和(sum_{j in k}c_i)都可以预处理出来,时间复杂度为(O(n3^n))

    这样太慢了,考虑不枚举子集,改为枚举点来转移,对于每一层我们按拓扑序来枚举每个点,类似01背包那样选或不选这个点来转移,若选了这个点,类似之前的dp,这个点不能在集合(S)中且这个点连出去的点都在集合(S)中,因为是按拓扑序来枚举的,所以不会出现两个点之间有一条边且出现在同一层,时间复杂度为(O(n^22^n))

    (O(n3^n)) Code

    #include<bits/stdc++.h>
    #define pii pair<int,int>
    #define ll long long
    #define pb push_back
    #define mp make_pair
    #define se second
    #define fi first
    using namespace std;
    const double eps=1e-8;
    const int mod=1e9+7;
    const int N=1e5+10;
    const int inf=1e9;
    int n,m;
    vector<int>g[20];
    int a[20],c[20];
    int sum[1<<20],gi[1<<20],dp[20][1<<20],f[20][1<<20];
    int main(){
        cin>>n>>m;
        for(int i=1,x,y,w;i<=m;i++){
            cin>>x>>y>>w;
            --x;--y;
            c[x]+=w;
            c[y]-=w;
            g[x].pb(y);
        }
        for(int i=0;i<(1<<n);i++){
            for(int j=0;j<n;j++) if(i>>j&1){
                sum[i]+=c[j];
            }
            for(int j=0;j<n;j++) if(i>>j&1){
                for(int x:g[j]) gi[i]|=1<<x;
            }
        }
        memset(dp,0x3f3f3f,sizeof dp);
        dp[0][0]=0;
        for(int i=1;i<=n;i++){
            for(int s=0;s<(1<<n);++s){
                for(int k=s;k;k=(k-1)&s){
                    if((gi[k]&(s^k))==gi[k]){
                        int cost=dp[i-1][s^k]+sum[k]*(i-1);
                        if(cost<dp[i][s]){
                            dp[i][s]=cost;
                            f[i][s]=k;
                        }
                    }
                }
            }
        }
        int s=(1<<n)-1;
        int mn=n;
        for(int i=1;i<=n;i++) if(dp[i][s]<dp[mn][s]) mn=i;
        for(int i=mn;i>=1;i--){
            int k=f[i][s];
            for(int j=0;j<n;j++) if(k>>j&1){
                a[j]=i-1;
            }
            s=s^k;
        }
        for(int i=0;i<n;i++) cout<<a[i]<<' ';
        cout<<endl;
        return 0;
    }
    

    (O(n^22^n)) Code

    #include<bits/stdc++.h>
    #define ll long long
    #define pb push_back
    using namespace std;
    const double eps=1e-8;
    const int mod=1e9+7;
    const int N=1e5+10;
    const int inf=1e9;
    int n,m;
    vector<int>g[20],v;
    int a[20],c[20],d[20],dp[20][20][1<<18],f[20][20][1<<18],bit[20];
    int main(){
        cin>>n>>m;
        for(int i=1,x,y,w;i<=m;i++){
            cin>>x>>y>>w;
            --x;--y;
            c[x]+=w;
            c[y]-=w;
            g[x].pb(y);
            ++d[y];
            bit[x]|=1<<y;
        }
        queue<int>q;
        for(int i=0;i<n;i++) if(d[i]==0) q.push(i);
        while(!q.empty()){
            int u=q.front();q.pop();
            v.pb(u);
            for(int x:g[u]){
                if(--d[x]==0) q.push(x);
            }
        }
        memset(dp,0x3f3f3f,sizeof dp);
        dp[0][0][0]=0;
        for(int i=0;i<n;i++) for(int j=0;j<=n;j++) for(int k=0;k<(1<<n);k++){
            if(j==n){
                if(dp[i+1][0][k]>dp[i][j][k]){
                    dp[i+1][0][k]=dp[i][j][k];
                    f[i+1][0][k]=-1;
                }
                continue;
            }
            int x=v[j];
            if(dp[i][j+1][k]>dp[i][j][k]){
                dp[i][j+1][k]=dp[i][j][k];
                f[i][j+1][k]=-1;
            }
            if(!(k>>x&1)&&(bit[x]&k)==bit[x]){
                int nk=k^(1<<x);
                if(dp[i][j+1][nk]>dp[i][j][k]+c[x]*i){
                    dp[i][j+1][nk]=dp[i][j][k]+c[x]*i;
                    f[i][j+1][nk]=k;
                }
            }
        }
        int x=1,y=0,s=(1<<n)-1;
        for(int i=1;i<=n;i++) for(int j=0;j<=n;j++) if(dp[i][j][s]<dp[x][y][s]) x=i,y=j;
        while(x||y||s){
            if(f[x][y][s]==-1){
                if(y==0){
                    x--;
                    y=n;
                }else y--;
            }else{
                int ns=f[x][y][s];
                int k=ns^s;
                for(int i=0;i<n;i++) if(k>>i&1){
                    a[i]=x;
                }
                s=ns;
                y--;
            }
        }
        for(int i=0;i<n;i++) cout<<a[i]<<' ';
        cout<<endl;
        return 0;
    }
    
  • 相关阅读:
    CF1109F Sasha and Algorithm of Silence's Sounds LCT、线段树
    Solution -「CF 757F」Team Rocket Rises Again
    Solution -「ZJOI2012」「洛谷 P2597」灾难
    Solution -「CF 156D」Clues
    「矩阵树定理」学习笔记
    Solution -「JSOI2008」「洛谷 P4208」最小生成树计数
    Solution -「SHOI2016」「洛谷 P4336」黑暗前的幻想乡
    Solution -「Code+#2」「洛谷 P4033」白金元首与独舞
    Solution -「HDU 5498」Tree
    呐~「多项式」全家桶
  • 原文地址:https://www.cnblogs.com/xyq0220/p/13855612.html
Copyright © 2011-2022 走看看