2019 ICPC Nanchang Regional B.Un divertido gráfico bipartito (presión estatal DP)

Título

Un gráfico bipartito con nn en cada ladon puntos, primero a la izquierdaiilos puntos tienen un atributomi m_imetroyo, Su valor en un gráfico es midi m_i ^ {d_i}metroyoreyo, Entre ellos di d_ireyo¿Es su grado en la figura (especialmente, si el grado es 0 00 , el valor es0 00 ), encuentre un subgrafo del gráfico bipartito para que el grado de cada punto de la derecha no sea0 00 y el valor total es el más pequeño, se emite el valor más pequeño. Si no hay solución, salida- 1 -1- 1
tiene varias restricciones(i, j) (i, j)( yo ,j ) representa el puntoii dela izquierdaen elsubgrafoyo yjjj no puede existir al mismo tiempo
garantía:

  1. El grado de cada punto en el lado izquierdo del gráfico bipartito original está en [1, 3] [1,3][ 1 ,3 ] entre.
  2. Ii a la izquierdai puntos yJJa la derechaEl lado derecho entre j puntos si y solo sii ≤ ji \ le jyoj

Rango de datos n ≤ 18, mi ≤ 100 n \ le 18, m_i \ le100norte1 8 ,metroyo1 0 0

Ideas para resolver problemas

Este rango de datos es fácil de pensar en la presión del estado DP, pero existe la dificultad de que necesita tanto el estado del punto izquierdo seleccionado previamente como el estado del punto derecho que no está seleccionado actualmente. Si usa binario para enumerar, entonces la complejidad Es 2 2 n 2 ^ {2n}22 n .
Tenga en cuenta que el título está garantizado:iia la izquierdai puntos yJJa la derechaEl lado derecho entre j puntos si y solo sii ≤ ji \ le jyoj
Luego, de pequeño a grande, seleccione los bordes de la izquierda y el punto actual esiiCuando i , el número correcto es[1, i - 1] [1, i-1][ 1 ,yo-1 ] puntos deben cubrirse y los puntos numerados [i + 1, n] a la izquierda aún no deben seleccionarse. Entonces, las longitudes binarias de estas dos partes suman exactamente n.
Entonces elegimos conectar los bordes para la transición de estado de pequeño a grande para los puntos de la izquierda, que esiiCuando selecciono el borde,máscara de máscaram a s k[0, i - 1] [0, i-1][ 0 ,yo-1 ] bit representa el punto izquierdo de la selección anterior,[i, n] [i, n][ yo ,El bit n ] representa el punto correcto que se ha seleccionado. Luego enumere el puntoiiSimplemente transfiera el estado del lado i- conectado.
Código:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int inf = 0x3f3f3f3f;
int dp[2][1<<18];
int val[20], ban[20];
vector<int> g[20];
char s[20];
int n;
void init(){
    
    
    scanf("%d", &n);
    for(int i = 0; i < n; ++i) g[i].clear();
    for(int i = 0; i < n; ++i) {
    
    
        scanf("%s", s);
        for(int j = 0; j < n; ++j) if(s[j] == '1') g[i].push_back(j);
    }
    for(int i = 0; i < n; ++i) {
    
    
        scanf("%s", s); ban[i] = 0;
        for(int j = 0; j < i; ++j) if(s[j] == '1') ban[i] |= (1<<j);
    }
    for(int i = 0; i < n; ++i) scanf("%d", &val[i]);
}
int sol(){
    
    
    int cur = 0, nxt = 1;
    memset(dp, 0x3f, sizeof dp);
    dp[cur][0] = 0;
    for(int i = 0; i < n; ++i){
    
    
        for(int mask = 0; mask < (1<<n); ++mask){
    
    
            int lstate = mask&((1<<i)-1);
            int rstate = mask&((1<<n)-(1<<i));
            if(dp[cur][mask] == inf) continue;
            // don't choose i
            if(rstate>>i&1) dp[nxt][(mask)^(1<<i)] = min(dp[nxt][(mask)^(1<<i)], dp[cur][mask]);
            if(ban[i]&lstate) continue;//can't choose i
            for(int t = 1; t < (1<<g[i].size()); ++t){
    
    
                int cost = 1;
                int ex = 0;
                for(int j = 0; j < g[i].size(); ++j){
    
    
                    int v = g[i][j];
                    if(t>>j&1) cost *= val[i], ex |= 1<<v;
                }
                int nstate = rstate|ex;
                if( !(nstate>>i&1) ) continue;
                dp[nxt][lstate|nstate] = min(dp[nxt][lstate|nstate], dp[cur][mask] + cost);
            }
        }
        swap(cur, nxt);
        memset(dp[nxt], 0x3f, sizeof dp[nxt]);
    }
    int ans = inf;
    for(int i = 0; i < (1<<n); ++i) ans = min(ans, dp[cur][i]);
    if(ans == inf) return -1;
    return ans;
}
int main()
{
    
    
    int T;cin>>T;
    while(T--){
    
    
        init();
        cout<<sol()<<endl;
    }
}

Supongo que te gusta

Origin blog.csdn.net/qq_43202683/article/details/104100695
Recomendado
Clasificación