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,0, sizeof(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, 0, sizeof(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, 0, sizeof(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<=0) return;
temp = ans[k];
flower[ans[k]] = true;
}
flower[temp] = true;
return ;
}
}