图论专题-状态压缩+搜索( dfs || bfs)

图论专题-状态压缩+搜索( dfs || bfs)_第1张图片

思路:
N只有22,所以可以用二进制压缩来表示点与点之间的联系,
例如标号为1的人认识标号为3与5还有7的人
标号为1的二进制压缩结果就为
0000000000000000001010101(标号为i的人肯定认识他自身)
可以用BFS暴力来找结果,dp[i]表示达到状态i的最小步数。
需要注意的就是必须当前状态now与( 1 << i ) 相 & 不为0(就是有一个1能够将这两个状态链接起来)
比如
10101 和 01010 就不行,因为你的 | 操作虽然能够得到11111,但是他们没有共同的1,无法让他们联系起来。

Code:

#include 
#define INF 0x3f3f3f3f
using namespace std;
const int AX = ( 1 << 22 );
int n , m ;
int MAXN;
int a[50];
int dp[AX];
int key[AX];
int res ; 

int from[AX];

queue<int>q;
void bfs(){
    while( !q.empty() ){
        int now = q.front() ; q.pop();
        if( now == MAXN ) return; 
        for( int i = 0 ; i < n ; i++ ){
            if( now & ( 1 << i ) ){
                int tmp = now | a[i];
                if( !dp[tmp] ){
                //  from[tmp] = i ;
                    dp[tmp] = dp[now] + 1 ;
                //  from[tmp] = now ;
                //  key[tmp] = i;
                    q.push(tmp);
                }   
            }
        }
    }
}

int main(){
    MAXN = 0 ;
    res = 0;
    scanf("%d%d",&n,&m);
    //memset( from , -1 , sizeof(from) );
//  memset( key , -1 , sizeof(key) );
    memset( dp , 0 ,sizeof(dp) );
    if( m == ( n * ( n - 1 ) / 2  ) ) return 0*printf("0\n");

    int x , y ; 
    for( int i = 0 ; i < n ; i++ ){
        a[i] |= ( 1 << i );
        MAXN |= ( 1 << i );
    }
    for( int i = 0 ; i < m ; i++ ){
        scanf("%d%d",&x,&y);
        x-- ; y-- ;
        a[x] |= ( 1 << y );
        a[y] |= ( 1 << x );
    }   

    for( int i = 0 ; i < n ; i++ ){
        q.push(a[i]);
        dp[a[i]] = 1 ;
        //key[a[i]] = i ;
    }
    bfs();
    //int pos = MAXN;
    //while( pos != -1 ){
//      res ++;
//      pos = from[pos];
//  }
    printf("%d\n",dp[MAXN]);
    //printf("%d\n",res);
    return 0 ;
}

如果答案集合确定,在某一步中无论先选剩下的哪个标号进行操作最终答案都相同,因为答案具有无序性,所以也可以用dfs来做
思路:dp[i][j] 记录(1<< i ) 和( 1 << j ) 状态联系起来后得到状态。
注意将上一层的状态复制给下一个状态。

Code:

#include 
#define INF 0x3f3f3f3f
using namespace std;
const int AX = ( 1 << 22 );
int n , m ;
int MAXN;
int a[50];
int dp[50][50];
int res ; 
int step;
void dfs( int x ){
    if( x > n ) return ; 
    if( x == n ){
        for( int i = 0 ; i < n ; i++ ){
            if( dp[x][i] != MAXN ) return;
        }
        res = min( res , step );
    }
    memcpy( dp[x+1] , dp[x] , sizeof(dp[x]) ); // 将x状态复制给x+1
    dfs( x + 1 );

    for( int i = 0 ; i < n ; i++ ){
        if( dp[x][x] & ( 1 << i ) ){
            dp[x+1][i] |= dp[x][x];
        }
    }
    step ++;
    dfs( x + 1 );
    step --;
}

int main(){
    MAXN = 0 ;
    res = INF;
    step = 0;
    scanf("%d%d",&n,&m);
    memset( dp , 0 , sizeof(dp) );
    if( m == ( n * ( n - 1 ) / 2  ) ) return 0*printf("0\n");

    int x , y ; 
    for( int i = 0 ; i < n ; i++ ){
        dp[0][i] |= ( 1 << i );
        MAXN |= ( 1 << i );
    }
    for( int i = 0 ; i < m ; i++ ){
        scanf("%d%d",&x,&y);
        x-- ; y-- ;
        dp[0][x] |= ( 1 << y );
        dp[0][y] |= ( 1 << x );  //初始是( 1 << 0 ) 到 ( 1 << y ) 的状态 
    }   

    dfs(0);
    printf("%d\n",res);
    return 0 ;
}

你可能感兴趣的:(搜索)