标签:
Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 539    Accepted Submission(s): 177
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <map>
#include <bitset>
#include <stack>
#include <queue>
#include <vector>
#include <bitset>
#include <set>
#define MM(a,b) memset(a,b,sizeof(a));
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
#define CT continue
#define SC scanf
char f[15][15];
int anc[16],flag[14],mp[12][12],cnta,ans,res;
int dx[]={0,0,1,-1},dy[]={1,-1,0,0},match[105],used[105];
vector<int> G[205];
int cas,r,l;
bitset<15> sta;
void add_edge(int u,int v)
{
    G[u].push_back(v);
    G[v].push_back(u);
    //if(sta==0) cout<<"u: "<<u<<" v:"<<v<<"\n";
}
bool dfs(int u)
{
     used[u]=1;
     for(int i=0;i<G[u].size();i++){
         int v=G[u][i],w=match[v];
         if(w<0||(!used[w]&&dfs(w))){
             match[u]=v;
             match[v]=u;
             return true;
         }
     }
     return false;
}
int bi_mactch()
{
    int res=0;
    MM(match,-1);
    for(int i=1;i<=r;i++)   for(int j=1;j<=l;j++){
      int k=(i-1)*l+j;
      if(match[k]<0){
         MM(used,0);
         if(dfs(k)) res++;
      }
    }
    return res;
}
int par[15];
int findr(int u)
{
    if(par[u]!=u)
       par[u]=findr(par[u]);
    return par[u];
}
void unite(int u,int v)
{
    int ru=findr(u),rv=findr(v);
    if(ru!=rv) par[ru]=rv;
}
int num=0;
void sear(int i,int j)
{
    if(f[i][j]>=‘0‘&&f[i][j]<=‘9‘){
       int k=f[i][j]-‘0‘;
       if(!flag[k]) return;
       mp[i][j]=-1;
       for(int d=0;d<4;d++){
              int tx=i+dx[d],ty=j+dy[d];
              if(f[tx][ty]>=‘0‘&&f[tx][ty]<=‘9‘){
                 int k2=f[tx][ty]-‘0‘;
                 if(flag[k2]) unite(k,k2);
              }
              else if(f[tx][ty]==‘.‘)  mp[tx][ty]=-1;
          }
    }
}
void bgraph()
{
    for(int i=1;i<=110;i++) G[i].clear();
    for(int i=1;i<=r;i++)
      for(int j=1;j<=l;j++)
        if(f[i][j]==‘.‘&&!mp[i][j]){
           num++;
           int k=(i-1)*l+j;
           //if(sta==0) cout<<"kk:"<<k<<"\n";
           if(f[i-1][j]==‘.‘&&!mp[i-1][j]) add_edge(k,k-l);
           if(f[i][j-1]==‘.‘&&!mp[i][j-1]) add_edge(k,k-1);
        }
}
void solve()
{
    ans=0;
    for(int k=0;k<=(1<<cnta)-1;k++){
        res=0;MM(mp,0);MM(flag,0);
        sta=k;
        for(int i=0;i<cnta;i++) if(sta[i]) {
            int w=anc[i+1];flag[w]=1;
            par[w]=w;
        }
        for(int i=1;i<=r;i++)   for(int j=1;j<=l;j++)  sear(i,j);
        for(int i=1;i<=cnta;i++)
            if(flag[anc[i]]&&par[anc[i]]==anc[i]) res++;
        num=0;bgraph();
        ans=max(ans,res+num-bi_mactch());
    }
}
int main()
{
    SC("%d",&cas);
    int kk=0;
    while(cas--){
        SC("%d%d",&r,&l);
        MM(flag,0);
        cnta=0;
        for(int i=1;i<=r;i++) {
            SC("%s",f[i]+1);
            for(int j=1;j<=l;j++)
              if(f[i][j]!=‘.‘){
                int k=f[i][j]-‘0‘;
                if(!flag[k]){
                    flag[k]=1;
                    anc[++cnta]=k;
                }
            }
        }
        solve();
        printf("Case #%d: %d\n",++kk,ans);
    }
    return 0;
}
分析:
1.先2^10=10^3暴力枚举选择的古代的田,选择了后,在用并查集维护一下,能产生的牧田数。
2.删除选择的古代的田周围的普通田地,再用下网格的二分图,考虑不想邻的连接一条边,那么最后显然成成了,求这样一个最大团
3.二分图的最大团=补图的最大点独立集合=顶点数-最大匹配数
标签:
原文地址:http://www.cnblogs.com/smilesundream/p/5932272.html