1. 程式人生 > >「ZJOI2007」「LuoguP1169」棋盤製作(並查集

「ZJOI2007」「LuoguP1169」棋盤製作(並查集

題目描述

國際象棋是世界上最古老的博弈遊戲之一,和中國的圍棋、象棋以及日本的將棋同享盛名。據說國際象棋起源於易經的思想,棋盤是一個8×88 \times 88×8大小的黑白相間的方陣,對應八八六十四卦,黑白對應陰陽。

而我們的主人公小Q,正是國際象棋的狂熱愛好者。作為一個頂尖高手,他已不滿足於普通的棋盤與規則,於是他跟他的好朋友小W決定將棋盤擴大以適應他們的新規則。

小Q找到了一張由N×MN \times MN×M個正方形的格子組成的矩形紙片,每個格子被塗有黑白兩種顏色之一。小Q想在這種紙中裁減一部分作為新棋盤,當然,他希望這個棋盤儘可能的大。

不過小Q還沒有決定是找一個正方形的棋盤還是一個矩形的棋盤(當然,不管哪種,棋盤必須都黑白相間,即相鄰的格子不同色),所以他希望可以找到最大的正方形棋盤面積和最大的矩形棋盤面積,從而決定哪個更好一些。

於是小Q找到了即將參加全國資訊學競賽的你,你能幫助他麼?

輸入輸出格式

輸入格式:

包含兩個整數NNN和MMM,分別表示矩形紙片的長和寬。接下來的NNN行包含一個N ×MN \ \times MN ×M的010101矩陣,表示這張矩形紙片的顏色(000表示白色,111表示黑色)。

輸出格式:

包含兩行,每行包含一個整數。第一行為可以找到的最大正方形棋盤的面積,第二行為可以找到的最大矩形棋盤的面積(注意正方形和矩形是可以相交或者包含的)。

輸入輸出樣例

輸入樣例#1: 複製
3 3
1 0 1
0 1 0
1 0 0
輸出樣例#1: 複製
4
6

說明

對於20%20\%20%的資料,N,M≤80N, M ≤ 80N,M80

對於40%40\%40%的資料,N,M≤400N, M ≤ 400N,M400

對於100%100\%100%的資料,N,M≤2000N, M ≤ 2000N,M2000

題解

某天中午去吃超好吃的魚粉,路上,一位選手問我們,

你知道懸線法是什麼嗎?!

我不知道,於是我問他是幹嘛的,於是他洋洋灑灑的擺出了這道題。

我kiao,這不就是我校傳了好幾屆的最大矩陣題嗎?!

原題差不多長這樣(點這裡!)

然後我把那道題改造了一下,成功AC。

————————————

跟原題不同的是,我們傳承字首和時的條件改為此位和上一位不同。

並且和左右接通時,判斷是否不同。如果相同就不連。

 1 /*
 2     qwerta
 3     P1169 [ZJOI2007]棋盤製作
 4     Accepted
 5     100
 6     程式碼 C++,1.5KB
 7     提交時間 2018-10-14 21:34:02
 8     耗時/記憶體
 9     29ms, 688KB
10 */
11 // luogu-judger-enable-o2
12 #include<iostream>
13 #include<cstdio>
14 #include<queue>
15 #include<cmath>
16 using namespace std;
17 #define R register
18 int s[2003];
19 int a[2003];
20 struct emm{
21     int nod,v;
22 };
23 struct cmp{
24     bool operator()(emm qaq,emm qwq){
25         return qaq.v<qwq.v;
26     }
27 };
28 priority_queue<emm,vector<emm>,cmp>q;
29 int siz[2003],fa[2003];
30 bool sf[2003];
31 int fifa(int x)
32 {
33     if(fa[x]==x)return x;
34     return fa[x]=fifa(fa[x]);
35 }
36 inline void con(int x,int y)
37 {
38     int u=fifa(x),v=fifa(y);
39     siz[u]+=siz[v];
40     fa[v]=u;
41     return;
42 }
43 inline int read()
44 {
45     char ch=getchar();
46     int x=0;
47     while(!isdigit(ch))ch=getchar();
48     if(isdigit(ch)){if(ch=='1')x=1;ch=getchar();}
49     return x;
50 }
51 int main()
52 {
53     //freopen("a.in","r",stdin);
54     int n,m;
55     scanf("%d%d",&n,&m);
56     int ansz=0,ansc=0;
57     for(R int i=1;i<=n;++i)
58     {
59         for(R int i=1;i<=m;++i)
60         {
61             int x=read();
62             if(a[i]+x==1)s[i]++;
63             else s[i]=1;
64             a[i]=x;
65             q.push((emm){i,s[i]});
66         }
67         for(R int i=1;i<=m;++i)
68           fa[i]=i,siz[i]=1,sf[i]=0;
69         a[0]=a[m+1]=2;
70         while(!q.empty())
71         {
72             int i=q.top().nod,x=q.top().v;q.pop();
73             sf[i]=1;
74             if(a[i-1]+a[i]==1&&sf[i-1])
75               con(i-1,i);
76             if(a[i]+a[i+1]==1&&sf[i+1])
77               con(i,i+1);
78             int fi=fifa(i),mi=min(siz[fi],x);
79             ansz=max(ansz,mi*mi);
80             ansc=max(ansc,siz[fi]*x);
81         }
82     }
83     printf("%d\n%d",ansz,ansc);
84     return 0;
85 }