HDU 5727 Necklace(全排列+二分图匹配)

时间:2021-09-15 23:51:49

http://acm.split.hdu.edu.cn/showproblem.php?pid=5727

题意:
现在有n个阳珠子和n个阴珠子,现在要把它们串成项链,要求是阴阳珠子间隔串,但是有些阴阳珠子在一起会让阳珠子变弱,现在问你串起来之后最少有几个阳珠子会变弱。

思路:

很考验思维的一道题目啊~

珠子一共也就9个,阴珠子是固定的,现在就可以先枚举阴珠子的排列顺序(可以用STL自带的全排列),然后对于阳珠子,看看它可以串在哪个位置(和前后两个阴珠子都可以相连),可以的话则连边。这样最后求个最大匹配即可。

不过这题很卡时间,在全排列的时候,因为是环排,所以只需要排n-1位即可,否则会TLE!

 #include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<cmath>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int INF = 0x3f3f3f3f;
const int maxn = 1e5 + ; int ans;
int n, m;
int a[];
bool unable[][];
bool vis[];
int mark[]; vector<int> G[]; bool match(int u)
{
for(int i=;i<G[u].size();i++)
{
int v=G[u][i];
if(!vis[v])
{
vis[v]=true;
if(mark[v]==- || match(mark[v]))
{
mark[v]=u;
return true;
}
}
}
return false;
} void solve()
{
for(int i=;i<;i++) G[i].clear();
for(int i=;i<=n;i++)
{
for(int j=;j<=n;j++)
{
int nxt=i,pre=i-;
if(pre==) pre=n;
if(!unable[j][a[pre]] && !unable[j][a[nxt]])
G[j].push_back(i);
}
} memset(mark,-,sizeof(mark));
int sum=;
for(int i=;i<=n;i++)
{
memset(vis,false,sizeof(vis));
if(match(i)) sum++;
}
ans=min(ans,n-sum);
} int main()
{
//freopen("in.txt","r",stdin);
while(~scanf("%d%d",&n,&m))
{
memset(unable,false,sizeof(unable));
while(m--)
{
int u,v;
scanf("%d%d",&u,&v);
unable[u][v]=true;
}
if(n== || m==) {puts("");continue;}
ans=INF;
for(int i=;i<=n;i++) a[i]=i;
do
{
solve();
}while(next_permutation(a+,a+n)); //因为是个环,所以只需要全排列(n-1)个数就好,少了一个*n的复杂度
printf("%d\n",ans);
}
return ;
}