hdu(3225) 求第k小匹配(09上海站F题)

来源:互联网 发布:知金教育怎么样 编辑:程序博客网 时间:2024/04/29 09:22

题目链接: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;}


原创粉丝点击