【题意】:求阳珠子最少的褪色的数量。
【解法】:假设现在是先把阴珠子排列了,排列后得到了n个槽位,编号1-n。现在就是要把n个阳珠子放到这个n个槽位里,使得阳珠子褪色最少。同样,我们再枚举阳珠子,如果阳珠子插到i槽位不会褪色,则在这个槽位和该阳珠子之间建一条边。最终,对于这个排列,我们得到了一个关于槽位和阳珠子的二分图(如果你还不知道二分图是什么,请看我上篇转载的博客)。要使褪色最少,即尽量使新建的二分图中的阳珠子放下去。所以求一下二分图的最大匹配res,res即为放下去的数量,n-res即为不得不褪色的阳珠子数量。
然后枚举所有阴珠子的排列(环排列,固定一个位置,其它用next_permutation)。求得所有的n-res,保留最小的那个即为阳珠子最少的褪色的数量
【!!!】
也是看到了HDU上竟然有将近700个人过了这题才来写的,又是一个没学过的知识点:二分图匹配,甚至我连什么是二分图都不知道。于是花了几个小时先搞明白了什么是二分图,什么是匹配,最后囫囵吞枣的把二分图匹配的匈牙利算法看了一遍,现在不敢深究其原理,只求会用基本的。学到现在才明白,ACM最重要的是什么?是积累!遇到不懂的不是留到日后,而是现在立刻就去百度,去查,去学!否则难有建树!
【代码】
/* ***********************************************
Author :angon
************************************************ */
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <stack>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
#define REP(i,k,n) for(int i=k;i<n;i++)
#define REPP(i,k,n) for(int i=k;i<=n;i++)
#define scan(d) scanf("%d",&d)
#define scann(n,m) scanf("%d%d",&n,&m)
#define mst(a,k) memset(a,k,sizeof(a));
#define LL long long
#define N 10
#define mod 100000007
/*
inline int read()
{
int s=0;
char ch=getchar();
for(; ch<'0'||ch>'9'; ch=getchar());
for(; ch>='0'&&ch<='9'; ch=getchar())s=s*10+ch-'0';
return s;
}
inline void print(int x)
{
if(!x)return;
print(x/10);
putchar(x%10+'0');
}
*/
int pos[N],m,n,mp[N][N],ans;
int head[N],tot;
struct node
{
int to,next;
}edge[N*N];
void addedge(int u,int v)
{
edge[tot].to=v;
edge[tot].next=head[u];
head[u]=tot++;
}
void init()
{
mst(head,-1);tot=0;
}
int vis[N],link[N];
bool dfs(int u)
{
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(!vis[v])
{
vis[v]=1;
if(link[v] == -1 || dfs(link[v]))
{
link[v]=u;
return 1;
}
}
}
return 0;
}
int hungry()
{
int res=0;
mst(link,-1);
for(int i=1;i<=n;i++)
{
mst(vis,0);
if(dfs(i)) res++;
}
return n-res;
}
int main()
{
//freopen("1005.in","r",stdin);
//freopen("out.txt","w",stdout);
while(~scann(n,m))
{
mst(mp,0);
REP(i,0,m)
{
int x,y;
scann(x,y); mp[x][y]=1;
}
if(n==0 || m==0)
{
puts("0");
continue;
}
REPP(i,1,n) pos[i]=i;
ans = 1112;
do
{
init();
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
int nx=i,pre=i-1;
if(pre==0) pre=n;
if(!mp[j][pos[nx]] && !mp[j][pos[pre]])
{
addedge(i,j);
}
}
}
ans = min(ans ,hungry());
}while(next_permutation(pos+1,pos+n));
printf("%d\n",ans);
}
return 0;
}