[hdu 3225] Flowers Placement

[hdu 3225] Flowers Placement

Hdu3225 Flowers Placement

题目大意

    原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=3225

    给定每个位置上不可以出现的数字,求N满足以上要求的第K(1<=K<=80)大的N(1<=N<=200)的全排列。

题目分析

    首先可以想到用深度优先搜索(DFS)来解决这个问题,但是显然不加优化的搜索是不可能在规定时限内完成题目要求的,所以必须考虑剪枝。

    全排列可以抽象为一个二分图匹配,点集V1为1~N,点集V2也为1~N。V1(位置)和V2(花)之间可以连上边。因此可以考虑剪枝:在深度搜索到第k位的时候,判断剩下的k+1~N位可否形成一个二分图匹配,若不可以则不继续深入搜索。并且由于此过程中一直只是在维护二分图匹配,每次只需要在改动的点上做一次增广就可以了,并不需要每次都进行完整的匈牙利过程。

关键词:

    二分图匹配、DFS、剪枝

小结:

1、  一图胜千言,注意画图

2、  数组的清空要仔细检查避免带来不必要的麻烦甚至是不易发现的bug。

 

代码:

hdu3225
#include <cstdio>
#include 
<cstdlib>
#include 
<algorithm>
const int maxn = 300;

int  result[maxn];            //记录V2中的点匹配的点的编号
bool state [maxn];            //记录V2中的每个点是否被搜索过
bool flower[maxn];            //记录第i盆花是否可以在排列中被使用 
bool map[maxn][maxn];    
int  ans[maxn];
int  N, M, K;

void init();
bool MaxMatch_DFS(int a, int k);
bool Perfect_Match();
bool check(int k);
void DFS(int k);

int main(){
    
int T,Cases;
    scanf(
"%d"&T);
    
for (Cases = 1; Cases<=T; Cases++){
        init();
        printf(
"Case #%d:", Cases);
        
if (!Perfect_Match()) {
            printf(
" -1\n", T);
            
continue;
        }

        DFS(
1);
        
if (K > 0) printf(" -1\n", T);
        
else {
            
for (int i=1; i<=N; i++) printf(" %d", ans[i]);
            printf(
"\n");
        }

    }

    system(
"pause");
    
return 0;
}


void init(){
    
int i,j,t;
    scanf(
"%d%d%d"&N, &M, &K);
    
for (i=1; i<=N; i++)
        flower[i] 
= true;
    
for (i=1; i<=N; i++)
        
for (j=1; j<=N; j++)
            map[i][j] 
= true;
    
for (i=1; i<=M; i++)
        
for (j=1; j<=N; j++){
            scanf(
"%d"&t);
            map[j][t] 
= false;
        }

    memset(ans,
0sizeof(int)*(N+1));
}


bool MaxMatch_DFS(int a, int k){
    
if (a<=k) return false;                            //即将放花的地方不可以比k小
    for (int i = 1; i <= N; i++){
        
if (map[a][i] && !state[i]){                //如果节点i与a相邻并且未被查找过
            state[i] = true;                        //标记i为已查找过
            if (result[i] == 0 || MaxMatch_DFS(result[i], k))
                
//如果i未在前一个匹配M中 i在匹配M中,但是从与i相邻的节点出发可以有增广路
                result[i] = a;                         //记录查找成功记录
                return true;                         //返回查找成功   
            }

        }

    }

    
return false;
}


bool Perfect_Match(){
    
int ans = 0, i;
    memset(result,
0,sizeof(int)*(N+1));
    
for (i = 1; i <= N; i++){
        memset(state, 
0sizeof(bool)*(N+1));             //清空上次搜索时的标记
        if (!MaxMatch_DFS(i, 0)) return false;                 //从节点i尝试扩展
    }

    
return true;
}


bool check(int k){
    
int  result_backup[maxn], i, j, t;
    
if (result[ans[k]] == k) return true;
    j 
= 0;
    
for (i=1; i<=N; i++){
        result_backup[i] 
= result[i];
        
if (result[i] == k) j = i;
    }

    t 
= result[ans[k]];
    result[ans[k]] 
= k;
    result[j] 
= 0;
    memset(state, 
0sizeof(bool)*(N+1)); 
    
if (MaxMatch_DFS(t, k)) return true;
    
else
        
for (i=1; i<=N; i++)
            result[i] 
= result_backup[i];
    
return false;
}


void DFS(int k){
    
int temp;
    
if ( K <= 0 ) return;
    ans[k] 
= 0;
    
if (k == N){
        
while (++ans[k]<=N)
            
if (flower[ans[k]] && map[k][ans[k]]) break;
        
--K;
        flower[ans[k]] 
= true;
        
return ;
    }

    
if (k != N){
        temp 
= ans[k];
        
while (++ans[k]<=N)
            
if (flower[ans[k]] && map[k][ans[k]] && check(k)){
                flower[ans[k]] 
= false;
                DFS(k
+1);
                
if (K<=0return;
                temp 
= ans[k];
                flower[ans[k]] 
= true;
            }

        flower[temp] 
= true;
        
return ;
    }

}

你可能感兴趣的:([hdu 3225] Flowers Placement)