HDU 5727 Necklace 环排+二分图匹配

这是从山东大学巨巨那里学来的做法

枚举下黑色球的排列总数是8!,然后八个白球可选的位置与左右两个黑球存不存在关系建图就行

这是原话,具体一点,每次生成环排,只有互不影响的才连边

最后:注重一点,n个数环排是(n-1)!

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <string.h>
#include <vector>
#include <map>
using namespace std;
typedef long long LL;
const int INF=0x3f3f3f3f;
const int N=2e5+5;
int pos[10],n,m,match[10],ret;
bool vis[10],used[10],g[10][10],mp[10][10];
bool dfs(int u){
  for(int v=1;v<=n;++v){
    if(!g[u][v]||used[v])continue;
    used[v]=true;
    if(match[v]==-1||dfs(match[v])){
      match[v]=u;
      return true;
    }
  }
  return false;
}
void solve(){
  memset(match,-1,sizeof(match));
  memset(g,false,sizeof(g));
  for(int i=2;i<=n;++i){
    for(int j=1;j<=n;++j){
      if(mp[pos[i]][j]||mp[pos[i-1]][j])
        continue;
      g[i][j]=true;
    }
  }
  for(int i=1;i<=n;++i){
    if(mp[pos[1]][i]||mp[pos[n]][i])
      continue;
    g[1][i]=true;
  }
  int ans=0;
  for(int i=1;i<=n;++i){
    memset(used,false,sizeof(used));
    if(dfs(i))++ans;
  }
  ret=min(ret,n-ans);
}
void get(int x){
  if(ret==0)return;
  if(x==n+1){solve();return;}
  for(int i=1;i<=n;++i){
    if(vis[i])continue;
    pos[x]=i;
    vis[i]=true;
    get(x+1);
    vis[i]=false;
  }
}
int main(){  
  vis[1]=true;pos[1]=1;
  while(~scanf("%d%d",&n,&m)){
     if(n==0){
      printf("0\n");
      continue;
     }
     memset(mp,0,sizeof(mp));
     while(m--){
      int u,v;
      scanf("%d%d",&u,&v);
      mp[v][u]=true;
     }
     ret=INF;
     get(2);
     printf("%d\n",ret);
  }
  return 0;
}
View Code

 

posted @ 2016-07-20 11:48  shuguangzw  阅读(371)  评论(0编辑  收藏  举报