51nod 1580 鋪管道(折線問題)

2021-08-08 03:29:58 字數 3641 閱讀 2049

1580 鋪管道

codeforces

基準時間限制:1.5 秒 空間限制:131072 kb 分值: 40 

難度:4級演算法題

現在要在乙個城市中鋪設管道。

這個城市是由 n×m 小方格組成的。每乙個小方格要麼是空的(管道可以鋪設在上面),要麼是實的(管道不能鋪在上面)。空的用』.』表示,實的用』#』表示。

管道鋪設的規則如下:

·        整條管道是形狀是寬度為1的折線;

·        管道只能鋪設在空的格仔上面;

·        管道的兩個端點只能在邊緣上,但是不能在角上;

·        管道最多只能轉兩個彎(90度);

·        在管道上的格仔有且只能有兩個是在邊緣上的;

·        如果管道是一條直線,那麼他的兩個端點必須是落在不同的邊上;

·        對於管道上的非邊緣格仔,每乙個格仔會有且僅有兩個相鄰的其它格仔在管道上;

·        對於管道上處於邊緣的格仔,僅有乙個相鄰的格仔處於管道上。

下面有一些合法的管道鋪設例子:

1

2

3

4

5

....#           

....#            

.*..#

*****

****..

***.

..# ..

..# *

...#

*.

# ...#           #

..*#            #

..*#

.....

...*

....*.

下面是一些非法鋪設的例子:

1

2

3

4

5

.**.#            

*...#            

.*.*#

.....

****..

*.*.

..# ..

..# *..

*# *.

# ...#            #

..*#            #

*.*#

.....

...*..

***.

這些例子中管道用』*』表示。

現在給定城市的地圖,請計算一下有多少種方法鋪設管道。

樣例解釋:

在這個樣例中,有三種方法鋪設管道(管道用'*'表示)。

1      

2

3

.*..*

....

.*#        

**#        

**#.*.

....*.

input

單組測試資料。

第一行有兩個整數 n,m (2≤n,m≤2000),表示城市地圖的高和寬。

接下來n行,每一行有m個字母,表示城市地圖。

如果字元是』.』,表示該格仔是空的,管道可以鋪設。

如果字元是』#』,表示該格仔是實的,管道不能鋪設。

output

輸出乙個整數,表示管道鋪設方案的種數。
input示例

樣例輸入1

3 3...

..#...

output示例

樣例輸出1

3

system message

(題目提供者)

visual c++的執行時限為:1500 ms ,空間限制為:131072 kb 

示例及語言說明請按這裡

允許其他 ac 的使用者檢視此**,分享**才能檢視別人的**並有機會獲得勳章

題意很繁瑣,問題就是求滿足題目描述的管道數量。一開始想的廣搜,果斷超時。。但是好像cf不會超時啊。

後來查了發正解,發現問題可以轉化為折線問題。我們可以把管道看做折線(其實沒啥區別)

然後滿足題意的折線無非4種。。借鑑乙個大佬的圖。。

然後我們就可以按照題目要求查詢滿足要求的直線了,為哦了避免重複計算,所以考慮先計算縱向的

然後摺疊矩陣,交換位置(可能說的不是很對,詞窮了),中間的細節很多,敲了半天一直wa。

然後借鑑了一位大佬的**:才避免了許多重複計算。很巧妙

#include#include#include#include#include#include#include#include#include#include#include#include#include#includeusing namespace std;

typedef long long ll;

#define inf 1000000000

#define mod 1000000007

#define maxn 2005

#define pi 3.1415926

#define lowbit(x) (x&-x)

#define eps 1e-9

char s[maxn];

bool a[maxn][maxn], b[maxn][maxn], c[maxn][maxn], d[maxn][maxn];

ll ans;

void solve(int n, int m, int flag)

ans += ((!c[i][j]) + (!d[i][j]))*tmp;

ans += ((!c[i][j] && !d[i][j - 1]) + (!c[i][j - 1] && !d[i][j]));

tmp += (!c[i][j - 1]) + (!d[i][j - 1]);//之後累加能組成下...右...上和上...右...下等折線

} if (!a[i][m] && flag)//加上從前邊任何一列開始為下...右...和上...右...的折線

ans += tmp + (!c[i][m - 1]) + (!d[i][m - 1]);//以及左右直達的直線

} if (flag)//在算其他型別折線的同事橫向直線順帶求出了,故直線只用再求一次 }

int main(void)

solve(n, m, 1);

for (i = 1;i <= n;i++)

for (j = 1;j <= m;j++)

b[j][i] = a[i][j];

memset(a, 0, sizeof(a));

for (i = 1;i <= m;i++)

for (j = 1;j <= n;j++)

a[i][j] = b[i][j];

solve(m, n, 0);

printf("%lld\n", ans);

return 0;

}

51nod 貪心入門

有若干個活動,第i個開始時間和結束時間是 si,fi 活動之間不能交疊,要把活動都安排完,至少需要幾個教室?分析 能否按照之一問題的解法,每個教室安排盡可能多的活動,即按結束時間排序,再貪心選擇不衝突的活動,安排乙個教室之後,剩餘的活動再分配乙個教室,繼續貪心選擇 反例 a 1,2 b 1,4 c ...

51nod 迷宮問題

1459 迷宮遊戲 基準時間限制 1 秒 空間限制 131072 kb 分值 0 難度 基礎題 你來到乙個迷宮前。該迷宮由若干個房間組成,每個房間都有乙個得分,第一次進入這個房間,你就可以得到這個分數。還有若干雙向道路鏈結這些房間,你沿著這些道路從乙個房間走到另外乙個房間需要一些時間。遊戲規定了你的...

51nod 硬幣遊戲

有乙個簡單但是很有趣的遊戲。在這個遊戲中有乙個硬幣還有一張桌子,這張桌子上有很多平行線 如下圖所示 兩條相鄰平行線之間的距離是1,硬幣的半徑是r,然後我們來拋硬幣到桌子上,拋下之後硬幣有時候會和一些直線相交 相切的情況也算是相交 有時候不會。請你來計算一下拋一次硬幣之後,該硬幣和直線相交數目的期望。...