排座位 二分圖最大匹配 搜索

搜索專項訓練賽 排座位

題目大意

有n位中國人和n位美國人開會,編號都是1~n。會桌是圓形的,有2n個座位。美國人和中國人必須交替就座,也就是相鄰兩個人的國籍不能相同。但是其中有些人有矛盾,挨在一起落座會不開心。給出這些矛盾關係,求出最少的不開心人數。

數據範圍

對於30% 的數據,0≤n≤5
對於 100% 的數據,0≤n≤9 , 0≤m≤n*n


看到數據範圍這麼小,不是狀壓DP就是搜索。這道題顯然是搜索,因爲很容易枚舉排列。

但是,如果僅僅是枚舉所有美國人和中國人的排列,時間複雜度會達到O((n!)2) ,只能過30%的數據。

如果只是枚舉一個國籍的人的排列,那麼只有O(n!) 種情況,即362880。這是完全能夠承受的。枚舉排列用內置的next_permutation就好。

假設枚舉的是美國人的排列,對於已知的一個排列怎樣得到最優解?這是一個比較經典的二分圖最大匹配模型,對於每個中國人,把他代表的點與不會使他產生矛盾的位置連邊,那麼用n減去最大匹配就是最小矛盾數。使用匈牙利算法,總時間複雜度O(n2n!)


#include<stdio.h>
#include<algorithm>
#include<cstring>
using namespace std;

int N,M,a[20],Ans=1e9,id;
bool mark[20][20];

int link[20],road[20];
bool Map[20][20];

bool Find(int x)
{
    int i;

    for(i=1;i<=N;i++)
    if(Map[x][i]&&road[i]!=id)
    {
        road[i]=id;
        if(link[i]==0||Find(link[i]))
        {
            link[i]=x;
            return true;
        }
    }
    return false;
}

void Solve()
{
    int i,j,tot=0,x,y;

    memset(Map,0,sizeof(Map));
    memset(road,0,sizeof(road));
    memset(link,0,sizeof(link));

    for(i=1;i<=N;i++)
    for(j=1;j<=N;j++)
    {
        x=a[j];
        y=j==N?a[1]:a[j+1];
        if(mark[i][x]||mark[i][y])continue;
        Map[i][j]=true;
    }

    id=0;
    for(i=1;i<=N;i++)
    {
        id++;
        if(Find(i))tot++;
    }

    Ans=min(Ans,N-tot);
}

int main()
{
    int i,tot;

    scanf("%d%d",&N,&M);

    for(i=1;i<=M;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        mark[x][y]=true;
    }

    for(i=1;i<=N;i++)a[i]=i;
    tot=1;for(i=1;i<=N;i++)tot*=i;

    for(i=1;i<=tot;i++)
    {
        Solve();
        if(i!=tot)next_permutation(a+1,a+N+1);
    }

    printf("%d",Ans);
}
發佈了105 篇原創文章 · 獲贊 23 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章