题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3225
题意描述:给你M*N的格子,N种花,每个格子种一种花,每一行种N中不同的花且每一列不能有相同的花出现,现在要求增加一行后也满足这个条件,让你求出按字典序第k大的一种种法,如果小于k种,那么直接输出-1
分析:该行的每一个位置都可以种一些满足条件的花,可以这样建图,每一个位置可以和多种花连边,求第k完备匹配即是答案,那么怎么求第k小完备匹配呢??
这里我们就可以用搜索来解,按字典序进行搜索,枚举出一种情况就判断该情况是否是一个完备匹配,这样求出来的第k个即为答案,显然这题不会这么水,毕竟是个匹配有关的题目,所以一定会用到匹配的,这里我们就可以用匹配算法来进行剪枝,我们先求出一个完备匹配,然后搜索每个位置能够种的花,假设当前位k置种了花i,那么判断k+1--n位置能不能形成一个完备匹配(即能否种出满足条件的花),若能那么当前位置可以种该花,继续搜索,若不能这返回
详情见代码:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int N=300;
bool vis[N][N];
int g[N][N];
int link[N];//link里面存放的是花对应放的位置的编号
bool used[N];
bool visit[N];
int n,link1[N],k,num,res[N];
bool find(int t,int limit)//找出比点得编号比limit大的匹配
{
if(t<=limit)return false;
int i;
for(i=1;i<=n;i++)
if(g[t][i]&&!used[i])
{
used[i]=true;
if(link[i]==-1||find(link[i],limit))
{
link[i]=t;
return true;
}
}
return false;
}
bool check(int pid,int fid) //判断假设pid和fid匹配之后,看pid+1--n个位置是否能够形成完备匹配
{
if(link[fid]==pid)return true;
int i,j;
for(i=1;i<=n;i++)
{
link1[i]=link[i];
if(link[i]==pid)j=i;
}
int t=link[fid]; link[fid]=pid; link[j]=-1; //将花fid和位置pid匹配,则与花原来匹配的位置则需从新匹配
memset(used,0,sizeof(used));
if(find(t,pid)) return true;
else for(i=1;i<=n;i++)
link[i]=link1[i];
return false;
}
bool dfs(int depth)
{
if(depth==n+1)
{
num++;
if(num==k)
return true;
return false;
}
for(int i=1;i<=n;i++)
if(!visit[i]&&g[depth][i]&&check(depth,i))
{
visit[i]=true;
res[depth]=i;
if(dfs(depth+1))return true;
visit[i]=false;
}
return false;
}
int main ()
{
int t,cas=1,m,i,j,x;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&m,&k);
memset(vis,0,sizeof(vis));
//vis[i][j]为1的时候表示第i行第j个位置种了第j种花
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
{
scanf("%d",&x);
vis[j][x]=true;
}
memset(g,0,sizeof(g));
for(j=1;j<=n;j++)
for(i=1;i<=n;i++)
if(!vis[i][j])
g[i][j]=1;//表示第j个位置可以放第i中花
printf("Case #%d:",cas++);
memset(link,-1,sizeof(link));
for(i=1;i<=n;i++)
{
memset(used,0,sizeof(used));
if(!find(i,0))
break;
}
if(i<=n){printf(" -1\n");continue;}
num=0;
memset(visit,0,sizeof(visit));
bool tag=dfs(1);
if(tag)
for(i=1;i<=n;i++)
printf(" %d",res[i]);
else printf(" -1");
printf("\n");
}
return 0;
}