[kuangbin带你飞]专题1-23 专题十 匹配问题(持续更新中)

  • Fire Net
    这一题和下面这题差不多,都可以看看,我感觉这种建图方式很强,反正是我想不到的类型。
    poj-226
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<string>
#include<vector>
#include<queue>
#include<algorithm>
#include<deque>
#include<map>
#include<stdlib.h>
#include<set>
#include<iomanip>
#include<stack>
#define ll long long
#define ms(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x & -x
#define fi first
#define se second
#define bug cout<<"----acac----"<<endl
#define IOS ios::sync_with_stdio(false), cin.tie(0),cout.tie(0)
using namespace std;
const int maxn = 1e3 + 50;
const int maxm = 1.5e5+50;
const double eps = 1e-7;
const double inf = 0x3f3f3f3f;
const ll  lnf  = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;
const  double pi=3.141592653589;
int x,y;
int mp[2550][2550],used[2550],nex[2550],c[55][55],b[55][55];
bool dfs(int zz)
{
    for(int j=1;j<=y;j++)
    {
        if(mp[zz][j]&&!used[j])
        {
            used[j]=1;
            if(nex[j]==0||dfs(nex[j]))
            {
                nex[j]=zz;
                return true;
            }
        }
    }
    return false;
}
int max_match()
{
    int sum=0;
    for(int i=1;i<=x;i++)
    {
        ms(used,0);
        sum+=dfs(i);
    }
    return sum;
}
char s[305][305];

int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        if(n==0)break;
       // init();
        for(int i=1;i<=n;i++)
        {
            scanf("%s",s[i]+1);
        }
       // ms(c,0);
       ms(nex,0);
        ms(mp,0);
        x=1;
        for(int i=1;i<=n;i++)//先遍历行,x的意思是这一行可以放的标号,但是碰到X时要要x++,原因是这碰到墙后之后这一行又可以放一个新的了
        {
            for(int j=1;j<=n;j++)
            {
                if(s[i][j]=='.')
                {
                    b[i][j]=x;
                }
                else if(s[i][j]=='X')
                {
                    x++;
                }
            }
            x++;//表示下一行也可以放新的了
        }
        y=1;
        for(int i=1;i<=n;i++)//和行相同,只是换成列了
        {
            for(int j=1;j<=n;j++)
            {
                if(s[j][i]=='.')
                {
                    c[j][i]=y;
                }
                else if(s[j][i]=='X')
                {
                    y++;
                }
            }
            y++;
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(s[i][j]=='.')
                mp[b[i][j]][c[i][j]]=1;//表示b[i][j]与c[i][j]互斥的,只能从中选一个,二分图匹配后就是最大匹配数
            }
        }
        printf("%d\n",max_match());
    }
    return 0;
}

  • The Accomodation of Students

这一题和上题差不多,会了上一题后这题只要解决No这一种情况就好了

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<string>
#include<vector>
#include<queue>
#include<algorithm>
#include<deque>
#include<map>
#include<stdlib.h>
#include<set>
#include<iomanip>
#include<stack>
#define ll long long
#define ms(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x & -x
#define fi first
#define se second
#define bug cout<<"----acac----"<<endl
#define IOS ios::sync_with_stdio(false), cin.tie(0),cout.tie(0)
using namespace std;
const int maxn = 1e5 + 50;
const int maxm = 1.5e5+50;
const double eps = 1e-7;
const double inf = 0x3f3f3f3f;
const ll  lnf  = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;
const  double pi=3.141592653589;
//mp[i][j]表示i与j之间连了一条边,used表示该店是否被访问,nex[i]表示这个点是否已经匹配
//二分图匹配最小顶点覆盖
int n,m;
int mp[430][430],used[maxn],nex[maxn];
bool dfs(int x)
{
    for(int j=1;j<=n;j++)
    {
        if(mp[x][j]&&!used[j])
        {
            used[j]=1;
            if(nex[j]==0||dfs(nex[j]))
            {
                nex[j]=x;
                return true;
            }
        }
    }
    return false;
}
int max_match()
{
    int sum=0;
    for(int i=1;i<=n;i++)
    {
        ms(used,0);
        sum+=dfs(i);
    }
    return sum;
}
int vis[maxn];

int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        bool flage=true;
        ms(mp,0);
        ms(nex,0);
        ms(vis,0);
        for(int i=1;i<=m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            mp[u][v]=1;
            if(vis[u]!=0&&vis[u]==vis[v])//如果本来是属于一个阵营,然后突然变成了敌对阵营了,那不是有内奸?所以输出No,好好体会一下,这题就知道怎么写了
            {
                flage=false;
            }
            vis[u]=1;
            vis[v]=2;
        }
        if(!flage)
        {
            printf("No\n");
            continue;
        }
        printf("%d\n",max_match());
    }
    return 0;
}



  • Courses HDU - 1083
    这一题没啥好说的,就是个裸体,找到最大匹配数就好了,如果最大匹配数等于课程数就是YES,如果小于就NO,不会有大于这种情况。
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<string>
#include<vector>
#include<queue>
#include<algorithm>
#include<deque>
#include<map>
#include<stdlib.h>
#include<set>
#include<iomanip>
#include<stack>
#define ll long long
#define ms(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x & -x
#define fi first
#define se second
#define bug cout<<"----acac----"<<endl
#define IOS ios::sync_with_stdio(false), cin.tie(0),cout.tie(0)
using namespace std;
const int maxn = 1e5 + 50;
const int maxm = 1.5e5+50;
const double eps = 1e-7;
const double inf = 0x3f3f3f3f;
const ll  lnf  = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;
const  double pi=3.141592653589;
//mp[i][j]表示i与j之间连了一条边,used表示该店是否被访问,nex[i]表示这个点是否已经匹配
//二分图匹配最小顶点覆盖
int n,m;
int mp[430][430],used[maxn],nex[maxn];
bool dfs(int x)
{
    for(int j=1;j<=m;j++)
    {
        if(mp[x][j]&&!used[j])
        {
            used[j]=1;
            if(nex[j]==0||dfs(nex[j]))
            {
                nex[j]=x;
                return true;
            }
        }
    }
    return false;
}
int max_match()
{
    int sum=0;
    for(int i=1;i<=n;i++)
    {
        ms(used,0);
        sum+=dfs(i);
    }
    return sum;
}
//int vis[maxn];

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        ms(mp,0);
        ms(nex,0);
        scanf("%d%d",&n,&m);
        int x;
        for(int i=1;i<=n;i++)
        {
            int k;
            scanf("%d",&k);
            for(int j=1;j<=k;j++)
            {
                scanf("%d",&x);
                mp[i][x]=1;
            }
        }
        if(max_match()==n)
        {
            printf("YES\n");
        }
        else
        {
            printf("NO\n");
        }
    }
    return 0;
}

  • 棋盘游戏
    在n*m的,里有k地方可以放“车”,在这里放"车"后横竖都都不能放“车”了,问最多可以放几个车,和有几个地方不放车,那么会改变车放的最大数量。
    跑完匈牙利后再枚举每个点,如果车的数量变了,那么就++。
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<string>
#include<vector>
#include<queue>
#include<algorithm>
#include<deque>
#include<map>
#include<stdlib.h>
#include<set>
#include<iomanip>
#include<stack>
#define ll long long
#define ms(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x & -x
#define fi first
#define se second
#define bug cout<<"----acac----"<<endl
#define IOS ios::sync_with_stdio(false), cin.tie(0),cout.tie(0)
using namespace std;
const int maxn = 1e4 + 50;
const int maxm = 1.5e5+50;
const double eps = 1e-7;
const double inf = 0x3f3f3f3f;
const ll  lnf  = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;
const  double pi=3.141592653589;
//mp[i][j]表示i与j之间连了一条边,used表示该店是否被访问,nex[i]表示这个点是否已经匹配
//二分图匹配最小顶点覆盖
int n,m,k;
int mp[105][105],used[maxn],nex[maxn];
bool dfs(int x)
{
    for(int j=1;j<=m;j++)
    {
        if(mp[x][j]&&!used[j])
        {
            used[j]=1;
            if(nex[j]==0||dfs(nex[j]))
            {
                nex[j]=x;
                return true;
            }
        }
    }
    return false;
}
int max_match()
{
    int sum=0;
    for(int i=1;i<=n;i++)
    {
        ms(used,0);
        sum+=dfs(i);
    }
    return sum;
}
//int vis[maxn];

int main()
{
    int cas=1;
    while(~scanf("%d%d%d",&n,&m,&k))
    {
        int u,v;
        ms(nex,0);
        ms(mp,0);
        for(int i=1;i<=k;i++)
        {
            scanf("%d%d",&u,&v);
            mp[u][v]=1;
        }
        int ans=max_match(),cnt=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                if(mp[i][j])
                {
                    mp[i][j]=0;
                    ms(nex,0);//这里一定要初始化,还有数组要开小一点,不然会T,但是我看别人的代码不一样,可以去看看别人的代码。
                    int temp=max_match();
                    if(temp!=ans)
                    {
                        cnt++;
                    }
                    mp[i][j]=1;
                }
            }
        }
        printf("Board %d have %d important blanks for %d chessmen.\n",cas++,cnt,ans);
    }
    return 0;
}
  • Swap HDU - 2819
    这一题我也不知道怎么说大家去看一下这个大佬的博客吧戳我进入
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<string>
#include<vector>
#include<queue>
#include<algorithm>
#include<deque>
#include<map>
#include<stdlib.h>
#include<set>
#include<iomanip>
#include<stack>
#define ll long long
#define ms(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x & -x
#define fi first
#define se second
#define bug cout<<"----acac----"<<endl
#define IOS ios::sync_with_stdio(false), cin.tie(0),cout.tie(0)
using namespace std;
const int maxn = 1e4 + 50;
const int maxm = 1.5e5+50;
const double eps = 1e-7;
const double inf = 0x3f3f3f3f;
const ll  lnf  = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;
const  double pi=3.141592653589;
//mp[i][j]表示i与j之间连了一条边,used表示该店是否被访问,nex[i]表示这个点是否已经匹配
//二分图匹配最小顶点覆盖
int n;
int mp[105][105],used[maxn],nex[maxn];//,a[55][55],b[55][55];
bool dfs(int x)
{
    for(int j=1;j<=n;j++)
    {
        if(mp[x][j]&&!used[j])
        {
            used[j]=1;
            if(nex[j]==0||dfs(nex[j]))
            {
                nex[j]=x;
                return true;
            }
       }
    }
    return false;
}
int max_match()
{
    int sum=0;
    for(int i=1;i<=n;i++)
    {
        ms(used,0);
        sum+=dfs(i);
    }
    return sum;
}

vector<int>ans1,ans2;
int main()
{
    while(~scanf("%d",&n))
    {
       ms(nex,0);
    // len=0;
       ans1.clear();
       ans2.clear();
       for(int i=1;i<=n;i++)
       {
           for(int j=1;j<=n;j++)
           {
               scanf("%d",&mp[i][j]);
           }
       }
       if(n!=max_match())
       {
           printf("-1\n");
       }
       else
       {
           int j;
           for(int i=1;i<=n;i++)
           {
               for(j=1;j<=n&&nex[j]!=i;j++);
               if(j!=i)
               {
                   ans1.push_back(i);
                   ans2.push_back(j);
                   swap(nex[i],nex[j]);
               }
           }
           printf("%d\n",ans1.size());
           for(int i=0;i<ans1.size();i++)
           {
               printf("C %d %d\n",ans1[i],ans2[i]);
           }
       }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qcccc_/article/details/107589621