NKOJ3869 排座位
时间限制 : - MS 空间限制 : 165536 KB
评测说明 : 1s
问题描述
何老板的公司有一个圆形会议室,会议室里有一个环形会议桌,共2*n个座位。
今天恰好有n位中国人和n位美国人来开会。为了表示尊重和平等,何老板要求美国人和中国人交替就座,也就是相邻两个人的国籍不能相同。
但是,何老板发现,其中有些人有矛盾,挨在一起落座会不开心。
何老板想知道,怎样安排座位,才能使得不开心的人数最少,请你帮他计算一下。
输入格式
第一行,两个整数n和m, n表示参会的人数为2*n, m表示其中有m对人有矛盾。
接下来m行,每行两个整数x和y,表示编号为x的中国人和编号为y的美国人有矛盾。
(中国人编号1到n,美国人编号也是1到n)
输出格式
一个整数,表示最少不开心的中国人的人数。
样例输入 1
3 4
1 1
1 2
1 3
2 1
样例输出 1
1
样例输入 2
3 7
2 2
1 2
3 3
1 1
2 1
2 3
1 3
样例输出 2
2
提示
【数据范围】
对于30% 的数据,0≤n≤5
对于 100% 的数据,0≤n≤9 , 0≤m≤n*n
来源 改编自multi 2016 necklace
思路:
数据超小,所以暴力
暴力枚举每个美国人的位置,然后计算中国人插入美国人中间的最小不高兴人数
1)、暴力枚举:permutation。
环的处理:固定一人,其余全排列
2)、计算最小不高兴人数:二分图。若第j号中国人能坐在i位的美国人后(即i号中国人与i位和i后面一位美国人都没有矛盾)则连一条j指向i的边。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int need=12;
int n,m;
int s[need];
int ne[need];
bool md[need][need];
//............................................
int la[need*need],en[need*need];
int tot,fi[need];
void add(int a,int b)
{
//cout<<a<<" "<<b<<endl;
tot++;
la[tot]=fi[a];
en[tot]=b;
fi[a]=tot;
}
//............................................
int d;
int link[need],vis[need];
bool find(int x)
{
for(int t=fi[x],y;t;t=la[t])
{
y=en[t];
if(vis[y]==d) continue;
vis[y]=d;
if(link[y]==0||find(link[y]))
{
link[y]=x;
return true;
}
}
return false;
}
//............................................
int main()
{
scanf("%d%d",&n,&m);
for(int i=1,a,b;i<=m;i++)
{
scanf("%d%d",&a,&b);
md[a][b]=true;
}
for(int i=1;i<n;i++) ne[i]=i+1;
ne[n]=1;
for(int i=1;i<=n;i++) s[i]=i;
int i,j,cnt,ans=1e9;
do{
for(i=1;i<=n;i++) fi[i]=0,vis[i]=0,link[i]=0;
tot=0;
for(i=1;i<=n;i++)//位置
{
for(j=1;j<=n;j++)//中国人
{
if(!md[j][s[i]]&&!md[j][s[ne[i]]]) add(j,i);
}
}
cnt=0;
for(d=1;d<=n;d++) if(find(d)) cnt++;
ans=min(ans,n-cnt);
if(ans==0) break;
}while(next_permutation(s+1,s+n));//s[i]表示坐i号位置的美国人编号
cout<<ans;
}