Description
将n个阳珠和n个阴珠交叉穿成一串,一些阳珠和阴珠若处于相邻位置则这个阳珠会变得黯淡,问所有串法中黯淡阳珠数最少为多少
Input
多组用例,每组用例第一行为两个整数n和m,分别表示有n个阳珠n个阴珠以及限制个数,之后m行每行两个整数x和y表示阳珠x和阴珠y相邻时x会变得暗淡,以文件尾结束输入(1<=n<=9,0<=m<=n*n)
Output
对于每组用例,输出所有串法中黯淡阳珠数的最小值
Sample Input
2 1
1 1
3 4
1 1
1 2
1 3
2 1
Sample Output
1
1
Solution
n最多只有9,用next_permutation函数(n-1)!枚举阴珠在串上的相对位置,阴珠位置确定之后,问题转化为往n个阴珠的n个间隙中插入阳珠,使得不变黯淡的阳珠数最多,将n个间隙看作一排点,n个阳珠看作一排点,如果阳珠i放在j间隙且与j间隙两端的阴珠相邻不变黯淡就在阳珠i和间隙j之间建一条边,对这张二分图跑二分匹配得到不变黯淡的阳珠数最大值ans,那么n-ans即为变黯淡的阳珠数最小值
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 11
int n,m,flag[maxn][maxn],yin[11];
int uN,vN;//u,v数目
int g[maxn][maxn];//编号是0~n-1的
int linker[maxn];
bool used[maxn];
bool dfs(int u)
{
int v;
for(v=0;v<vN;v++)
if(g[u][v]&&!used[v])
{
used[v]=true;
if(linker[v]==-1||dfs(linker[v]))
{
linker[v]=u;
return true;
}
}
return false;
}
int hungary()
{
int res=0;
int u;
memset(linker,-1,sizeof(linker));
for(u=0;u<uN;u++)
{
memset(used,0,sizeof(used));
if(dfs(u)) res++;
}
return res;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
if(!n)
{
printf("0\n");
continue;
}
memset(flag,0,sizeof(flag));
while(m--)
{
int a,b;
scanf("%d%d",&a,&b);
flag[a][b]=1;
}
for(int i=1;i<=n;i++)yin[i]=i;
int ans=n;
do
{
memset(g,0,sizeof(g));
uN=vN=n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
int k=i==n?1:i+1;
if(!flag[j][yin[i]]&&!flag[j][yin[k]])g[i-1][j-1]=1;
}
int temp=n-hungary();
ans=min(ans,temp);
}while(next_permutation(yin+2,yin+n+1));
printf("%d\n",ans);
}
return 0;
}