蒸發水學

題目描述

衆所周知,TerryHu 是一位大佬,他平時最喜歡作的事就是蒸發學水。
機房的位置一共有n 行m 列,一開始每一個位置都有一滴學水,TerryHu 決定在每個時刻選擇
一滴學水進行蒸發,直到機房裏再也不存在學水。
TerryHu 想知道在每一個時刻以後,機房裏剩下的學水構成了幾個聯通塊。

輸入

第一行包含2 個正整數n,m。
以後n 行每行包含m 個正整數Aij,表示第i 行第j 列的學水在時刻Aij 被蒸發,保證{A}構成了一個n *m 的排列。

輸出

共n * m 行每行包含1 個整數ansi,時刻i 以後剩下的學水構成的聯通塊的數量。

樣例輸入

2 2
1 3
4 2

樣例輸出

1
2
1
0

題解

1.暴力求解法 (DFS)html

對於每一時刻的局面,能夠抽象成一個圖。問題就是分別求每一時刻圖中連通份量的個數。如何求圖的連通份量的個數呢?能夠使用深度優先搜索DFS。假設圖中節點數爲N*M,那麼每一時刻都須要遍歷N*M節點來求取連通份量個數。一樣,咱們有N*M個時刻。最終的算法複雜度爲O( (N*M)2 )。ios

2.並查集算法

咱們先來看一看何爲並查集,這裏我再也不贅述,分享一篇好文章,那麼如何利用並查集優化問題求解呢,思路來自於這裏優化

實現

 

  1 #include <iostream>
  2 
  3 using namespace std;
  4 
  5 const int MAXSIZE = 1000*1000+1;
  6 int uset[MAXSIZE];
  7 int answer[MAXSIZE];
  8 pair<short,short> valueToIndex[MAXSIZE];
  9 const int dx[]={-1,0,0,1},dy[]={0,-1,1,0};
 10 
 11 //void makeSet(int size) {
 12 //   for(int i = 1;i <= size;i++)  uset[i] = -MAXSIZE;
 13 //}
 14 
 15 int find(int x) {
 16     int p = x, t;
 17     while (uset[p] > 0) p = uset[p];
 18     while (x != p ) {
 19         t = uset[x];
 20         uset[x] = p;
 21         x = t;
 22     }
 23     return x;
 24 }
 25 
 26 void unionSet(int x, int y) {
 27     if ((x = find(x)) == (y = find(y))) return;
 28     if (uset[x] < uset[y]) {
 29         uset[x] += uset[y];
 30         uset[y] = x;
 31     } else {
 32         uset[y] += uset[x];
 33         uset[x] = y;
 34     }
 35 }
 36 
 37 void unionSetRoot(int x,int y)
 38 {
 39     if (uset[x] < uset[y]) {
 40         uset[x] += uset[y];
 41         uset[y] = x;
 42     } else {
 43         uset[y] += uset[x];
 44         uset[x] = y;
 45     }
 46 }
 47 
 48 int raw,col;
 49 int main()
 50 {
 51   
 52    scanf("%d%d",&raw,&col);
 53    int size = raw * col;
 54    //makeSet(size);
 55   
 56    for(short i=1;i<=raw;i++)
 57     for(short j=1;j<=col;j++)
 58     {
 59         int value;
 60         scanf("%d",&value);
 61         valueToIndex[value] = make_pair(i,j);
 62     }
 63     
 64     for(int evaWater=size-1;evaWater>=1;evaWater--)
 65     {
 66         int lastEvaWater = evaWater+1;
 67         int x = valueToIndex[lastEvaWater].first;
 68         int y = valueToIndex[lastEvaWater].second;
 69         int lastValueIndex = (x-1)*col +y;
 70         uset[lastValueIndex] = -1;
 71         answer[evaWater] = answer[lastEvaWater]+1;
 72        
 73         for(int dir=0;dir<4;dir++)
 74         {
 75             int tx=x+dx[dir],ty=y+dy[dir];
 76             
 77             if(tx >=1&& tx <=raw && ty>=1 && ty<= col )
 78             {
 79                 int los =(tx-1)*col+ty;
 80                
 81                 if( uset[los] !=0 )
 82                 {
 83                     int key = find(los);
 84                     int last = find(lastValueIndex);
 85                     if(last != key)
 86                     {
 87                         unionSetRoot(last,key);
 88                         answer[evaWater]--;
 89                     }
 90                         
 91                 }
 92                
 93             }
 94         }
 95         
 96       
 97     }   
 98         
 99     
100   for (int i=1;i<=size;i++)
101         printf("%d\n",answer[i]);
102    
103    return 0;
104 }

代碼寫得很清晰,一共大概100行,主要是定義並查集,和運用並查集檢測周邊四個點的集合數。spa

這代碼能夠經過CCF的1000*1000 1s評測,運行時間大概在700-800ms,使用內存10M。使用內存數在全部實現中最少,可是時間不是最少。排名第一的同窗大概在450ms左右。這個我不清楚如何作到在消除者300ms的差距,由於300ms差距不是簡簡單單優化細節能夠作的。就目測他們應該是保存了更多的數據。.net

拋磚引玉

有沒有同窗還能更進一步的優化算法或是有更好的想法,爭取再砍下去一半時間。期待你的回覆~~~~~忘不吝賜教~~~~~code

相關文章
相關標籤/搜索