1. 程式人生 > >2016-2017 CT S03E01: Codeforces Trainings Season 3 Episode 1 J Wrong Answer 最大獨立集

2016-2017 CT S03E01: Codeforces Trainings Season 3 Episode 1 J Wrong Answer 最大獨立集

題意:

一個最大為2000*2000的矩陣,有h個橫著的單詞,v個豎著單詞,橫著的可能與豎著的有交叉,交叉的字元只能選其一放在格子內,問怎樣選擇才能使矩陣內單詞的數量最多,輸出最多有多少個。(注意同一行的單詞不會有交叉)

解法:

最大獨立集,因為橫著的與橫著不會有交叉,豎著的沒有,所以可以把橫著的單詞放在一邊,豎著的放在另一邊,橫著的與豎著的交叉點是不同字母的進行連邊。跑一遍二分匹配,每一個匹配就可以理解成這條邊匹配的兩個點只能有一個成立。最後的答案就是總共的點數減去匹配數就行了。

#include <bits/stdc++.h>
using namespace std;
const int N = 2000+10;

struct node{
    int v,next;
}E[N*100];
int h,v,top;
char s[N][N];  ///存單詞的圖
int head[N];
int num[N][N]; ///存單詞的編號
bool vis[N];
int match[N];  ///存二分匹配的點

void Init()
{
    top = 0;
    for(int i = 0;i < N;i++){
        head[i] = match[i] = -1;
        for(int j = 0;j < N;j++){
            s[i][j] = '\0';
            num[i][j] = 0;
        }
    }
}

void add(int u,int v)
{
    E[top].v = v;
    E[top].next = head[u];
    head[u] = top++;
}

bool dfs(int u)
{
    for(int i = head[u];i != -1;i = E[i].next){
        int v = E[i].v;
        if(vis[v]) continue;
        vis[v] = true;
        if(match[v] == -1 || dfs(match[v])){
            match[v] = u;
            return true;
        }
    }
    return false;
}

void xyl()
{
    int ans = 0;
    for(int i = 1;i <= h;i++){
        memset(vis,false,sizeof vis);
        if(dfs(i)){
            ans++;
        }
    }
    ans = h+v-ans;
    printf("%d\n",ans);
}

int main(void)
{
    int T;
    scanf("%d",&T);
    char str[1010];
    while(T--){
        Init();
        scanf("%d%d",&h,&v);   ///總共有h+v個點
        for(int i = 1;i <= h;i++){
            int x,y;
            scanf("%d%d%s",&x,&y,str);
            swap(x,y);
            int len = strlen(str);
            for(int j = 0;j < len;j++){
                if(s[x][y+j] != str[j] && num[x][y+j] != 0){
                    add(num[x][y+j],i);
                    add(i,num[x][y+j]);
                }
                s[x][y+j] = str[j];
                num[x][y+j] = i;
            }
        }
        for(int i = 1;i <= v;i++){
            int x,y;
            scanf("%d%d%s",&x,&y,str);
            swap(x,y);
            int len = strlen(str);
            for(int j = 0;j < len;j++){
                if(s[x+j][y] != str[j] && num[x+j][y] != 0){ ///只有橫著與豎著交叉點字元不一樣才建邊
                    add(num[x+j][y],h+i);
                    add(h+i,num[x+j][y]);
                }
                s[x+j][y] = str[i];
                num[x+j][y] = h+i;
            }
        }
        xyl();  ///匈牙利
    }
    return 0;
}