2016-2017 CT S03E01: Codeforces Trainings Season 3 Episode 1 J Wrong Answer 最大獨立集
阿新 • • 發佈:2019-01-27
題意:
一個最大為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; }