D - Swap Free Gym - 102423D 二分图性质:补图最大团 = 点的个数 - 最大匹配数

题意:给你一个串的某些全排列,没有重的,让你求一个最大的集合能有多少个元素,集合的满足条件:交换一个串的任意两个位置上的字母,不能变成集合里的另一个串。

 

思路:如果一个串不能通过交换一次字母位置变成另一个串,就让这两个串建边。建好图之后,找一个最大完全图,表示任意两个都不能通过交换变成相同的串。但是提交后发现找最大团的算法会TLE,就要用到题目的性质了。补图最大团 = 点的个数 - 最大匹配数,这样我们就让能交换到达的建边。

#include<bits/stdc++.h>
#define pb push_back
using namespace std;
const int maxn = 505;
vector<int> ma[maxn];
char MAP[550][30];
int link[maxn];
bool vis[maxn];

bool dfs(int x){
    int len = ma[x].size() - 1;
    for(int i = 0; i <= len; i++){
        int v = ma[x][i];
        if(vis[v]) continue;
        vis[v] = 1;
        if(!link[v] || dfs(link[v])){
            link[v] = x;
            link[x] = v;
            return 1;
        }
    }
    return 0;
}

int solve(int n){
    int ans = 0;
    for(int i = 1; i <= n; i++){
        if(link[i]) continue;
        for(int j = 1; j <= n; j++) vis[j] = 0;
        if(dfs(i)) ans++;
    }
    return n - ans;
}

int main(){
    int n;
    scanf("%d",&n); getchar();
    for(int i = 1;i <= n;i++){
        gets(MAP[i]);
    }
    int len = strlen(MAP[1]);
    for(register int i = 1;i <= n;i++){
        for(register int j = i + 1;j <= n;j++){
            int sum = 0;
            for(register int k = 0;k < len;k++){
                if(MAP[i][k] != MAP[j][k]){
                    sum++;
                    if(sum > 2) break;
                }
            }
            if(sum == 2) {
                ma[i].pb(j);
                ma[j].pb(i);
            }
        }
    }
    printf("%d\n",solve(n));
    return 0;
}

 

posted @ 2019-11-26 17:50  philo_zhou  阅读(277)  评论(0编辑  收藏  举报