搜索專項訓練賽 排座位
題目大意
有n位中國人和n位美國人開會,編號都是1~n。會桌是圓形的,有2n個座位。美國人和中國人必須交替就座,也就是相鄰兩個人的國籍不能相同。但是其中有些人有矛盾,挨在一起落座會不開心。給出這些矛盾關係,求出最少的不開心人數。
數據範圍
對於30% 的數據,0≤n≤5
對於 100% 的數據,0≤n≤9 , 0≤m≤n*n
看到數據範圍這麼小,不是狀壓DP就是搜索。這道題顯然是搜索,因爲很容易枚舉排列。
但是,如果僅僅是枚舉所有美國人和中國人的排列,時間複雜度會達到
如果只是枚舉一個國籍的人的排列,那麼只有
假設枚舉的是美國人的排列,對於已知的一個排列怎樣得到最優解?這是一個比較經典的二分圖最大匹配模型,對於每個中國人,把他代表的點與不會使他產生矛盾的位置連邊,那麼用n減去最大匹配就是最小矛盾數。使用匈牙利算法,總時間複雜度
#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);
}