pseudopolynomial time คืออะไร? แตกต่างจากพหุนามเวลาอย่างไร?


101

คืออะไรเวลา pseudopolynomial ? แตกต่างจากพหุนามเวลาอย่างไร? อัลกอริทึมบางอย่างที่ทำงานในเวลาหลอกมี runtimes เช่น O (nW) (สำหรับปัญหา 0/1 Knapsack ) หรือ O (√n) (สำหรับการแบ่งการทดลอง ) ทำไมไม่นับว่าเป็นพหุนามเวลา?


คำตอบ:


254

เพื่อให้เข้าใจถึงความแตกต่างระหว่างเวลาพหุนามและเวลาเทียมเราต้องเริ่มต้นด้วยการกำหนดความหมายของ "เวลาพหุนาม" อย่างเป็นทางการ

สัญชาตญาณทั่วไปสำหรับเวลาพหุนามคือ "เวลา O (n k ) สำหรับบาง k" ตัวอย่างเช่นการเรียงลำดับการเลือกจะทำงานในเวลา O (n 2 ) ซึ่งเป็นเวลาแบบพหุนามในขณะที่การแก้TSPแบบ brute-force จะใช้เวลา O (n · n!) ซึ่งไม่ใช่เวลาพหุนาม

เวลาทำงานเหล่านี้ล้วนอ้างถึงตัวแปร n บางตัวที่ติดตามขนาดของอินพุต ตัวอย่างเช่นในการเรียงลำดับการเลือก n หมายถึงจำนวนองค์ประกอบในอาร์เรย์ในขณะที่ใน TSP n หมายถึงจำนวนโหนดในกราฟ เพื่อสร้างมาตรฐานของคำจำกัดความของความหมายที่แท้จริงในบริบทนี้นิยามอย่างเป็นทางการของความซับซ้อนของเวลากำหนด "ขนาด" ของปัญหาดังนี้:

ขนาดของอินพุตสำหรับปัญหาคือจำนวนบิตที่ต้องใช้ในการเขียนอินพุตนั้น

ตัวอย่างเช่นหากอินพุตไปยังอัลกอริทึมการเรียงลำดับเป็นอาร์เรย์ของจำนวนเต็ม 32 บิตขนาดของอินพุตจะเป็น 32n โดยที่ n คือจำนวนรายการในอาร์เรย์ ในกราฟที่มีโหนดโหนดและขอบ m อินพุตอาจถูกระบุเป็นรายการของโหนดทั้งหมดตามด้วยรายการของขอบทั้งหมดซึ่งจะต้องใช้บิตΩ (n + m)

จากคำจำกัดความนี้คำจำกัดความอย่างเป็นทางการของเวลาพหุนามมีดังต่อไปนี้:

อัลกอริทึมทำงานในเวลาพหุนามถ้ารันไทม์เป็น O (x k ) สำหรับค่าคงที่ k โดยที่ x หมายถึงจำนวนบิตของอินพุตที่กำหนดให้กับอัลกอริทึม

เมื่อทำงานกับอัลกอริทึมที่ประมวลผลกราฟรายการต้นไม้ ฯลฯ คำจำกัดความนี้จะเห็นด้วยกับนิยามทั่วไปไม่มากก็น้อย ตัวอย่างเช่นสมมติว่าคุณมีอัลกอริทึมการเรียงลำดับที่จัดเรียงอาร์เรย์ของจำนวนเต็ม 32 บิต หากคุณใช้บางอย่างเช่นการเรียงลำดับการเลือกเพื่อทำสิ่งนี้รันไทม์ซึ่งเป็นฟังก์ชันของจำนวนองค์ประกอบอินพุตในอาร์เรย์จะเป็น O (n 2 ) แต่ n จำนวนองค์ประกอบในอาร์เรย์อินพุตสอดคล้องกับจำนวนบิตอินพุตอย่างไร? ดังที่ได้กล่าวไว้ก่อนหน้านี้จำนวนบิตของอินพุตจะเป็น x = 32n ดังนั้นหากเราแสดงรันไทม์ของอัลกอริทึมในรูปของ x แทนที่จะเป็น n เราจะได้ว่ารันไทม์คือ O (x 2 ) ดังนั้นอัลกอริทึมจึงทำงานในเวลาพหุนาม

ในทำนองเดียวกันสมมติว่าคุณทำการค้นหาเชิงลึกก่อนบนกราฟซึ่งใช้เวลา O (m + n) โดยที่ m คือจำนวนขอบในกราฟและ n คือจำนวนโหนด สิ่งนี้เกี่ยวข้องกับจำนวนบิตอินพุตที่กำหนดอย่างไร? ถ้าเราสมมติว่าอินพุตถูกระบุเป็นรายการ adjacency (รายการของโหนดและขอบทั้งหมด) ดังที่กล่าวไว้ก่อนหน้านี้จำนวนบิตอินพุตจะเป็น x = Ω (m + n) ดังนั้นรันไทม์จะเป็น O (x) ดังนั้นอัลกอริทึมจึงทำงานในเวลาพหุนาม

อย่างไรก็ตามสิ่งต่าง ๆ พังทลายลงเมื่อเราเริ่มพูดถึงอัลกอริทึมที่ทำงานกับตัวเลข ลองพิจารณาปัญหาในการทดสอบว่าตัวเลขเป็นจำนวนเฉพาะหรือไม่ ด้วยตัวเลข n คุณสามารถทดสอบว่า n เป็นไพรม์หรือไม่โดยใช้อัลกอริทึมต่อไปนี้:

function isPrime(n):
    for i from 2 to n - 1:
        if (n mod i) = 0, return false
    return true

แล้วความซับซ้อนของเวลาของรหัสนี้คืออะไร? วงในนั้นจะรัน O (n) ครั้งและแต่ละครั้งจะทำงานจำนวนหนึ่งเพื่อคำนวณ n mod i (ในฐานะขอบเขตบนที่อนุรักษ์นิยมจริงๆสิ่งนี้สามารถทำได้ในเวลา O (n 3 )) ดังนั้นอัลกอริทึมโดยรวมนี้จะทำงานในเวลา O (n 4 ) และอาจเร็วกว่ามาก

ในปี 2004 นักวิทยาศาสตร์คอมพิวเตอร์สามคนได้ตีพิมพ์บทความชื่อPRIMES is in P โดยให้อัลกอริธึมเวลาพหุนามสำหรับการทดสอบว่าตัวเลขเป็นจำนวนเฉพาะหรือไม่ ถือว่าเป็นผลลัพธ์ที่สำคัญ แล้วเรื่องใหญ่ล่ะ? เราไม่มีอัลกอริทึมเวลาพหุนามสำหรับสิ่งนี้หรือไม่?

น่าเสียดายที่เราไม่ จำไว้ว่าคำจำกัดความอย่างเป็นทางการของความซับซ้อนของเวลาพูดถึงความซับซ้อนของอัลกอริทึมซึ่งเป็นฟังก์ชันของจำนวนบิตของอินพุต อัลกอริทึมของเราทำงานในเวลา O (n 4 ) แต่นั่นคือฟังก์ชันของจำนวนบิตอินพุตคืออะไร? การเขียนจำนวน n ใช้ O (log n) บิต ดังนั้นถ้าเราให้ x เป็นจำนวนบิตที่ต้องใช้ในการเขียนอินพุต n รันไทม์ของอัลกอริทึมนี้คือ O (2 4x ) ซึ่งไม่ใช่พหุนามใน x

นี่คือหัวใจของความแตกต่างระหว่างเวลาพหุนามกับเวลาเทียม ในแง่หนึ่งอัลกอริทึมของเราคือ O (n 4 ) ซึ่งดูเหมือนพหุนาม แต่ในทางกลับกันภายใต้นิยามอย่างเป็นทางการของเวลาพหุนามไม่ใช่เวลาพหุนาม

หากต้องการทราบสัญชาตญาณว่าเหตุใดอัลกอริทึมจึงไม่ใช่อัลกอริทึมเวลาพหุนามให้คิดถึงสิ่งต่อไปนี้ สมมติว่าฉันต้องการให้อัลกอริทึมต้องทำงานมาก ๆ ถ้าฉันเขียนข้อมูลเช่นนี้:

10001010101011

จากนั้นจะใช้เวลาในกรณีที่เลวร้ายที่สุดพูดTเพื่อให้เสร็จสมบูรณ์ ถ้าตอนนี้ฉันเพิ่มบิตเดียวต่อท้ายตัวเลขดังนี้:

100010101010111

รันไทม์ตอนนี้ (ในกรณีที่แย่ที่สุด) จะเป็น 2T ฉันสามารถเพิ่มจำนวนงานเป็นสองเท่าที่อัลกอริทึมทำได้เพียงแค่เพิ่มอีกหนึ่งบิต!

อัลกอริทึมทำงานในpseudopolynomial timeหากรันไทม์เป็นพหุนามบางค่าในค่าตัวเลขของอินพุตแทนที่จะเป็นจำนวนบิตที่ต้องการเพื่อแสดง อัลกอริธึมการทดสอบที่สำคัญของเราคืออัลกอริธึมเวลาเทียมเนื่องจากรันในเวลา O (n 4 ) แต่ไม่ใช่อัลกอริธึมเวลาพหุนามเนื่องจากเป็นฟังก์ชันของจำนวนบิต x ที่จำเป็นในการเขียนอินพุตรันไทม์จึงเป็น O (2 4x ) เหตุผลที่กระดาษ "PRIMES อยู่ใน P" มีความสำคัญมากก็คือรันไทม์ (โดยประมาณ) O (log 12 n) ซึ่งตามฟังก์ชันของจำนวนบิตคือ O (x 12 )

แล้วทำไมเรื่องนี้? เรามีอัลกอริธึมเวลาหลอกหลายตัวสำหรับการหาตัวประกอบจำนวนเต็ม อย่างไรก็ตามอัลกอริทึมเหล่านี้เป็นอัลกอริธึมเวลาเอ็กซ์โปเนนเชียลที่พูดในทางเทคนิค สิ่งนี้มีประโยชน์มากสำหรับการเข้ารหัส: หากคุณต้องการใช้การเข้ารหัส RSA คุณต้องวางใจได้ว่าเราไม่สามารถแยกตัวประกอบตัวเลขได้อย่างง่ายดาย ด้วยการเพิ่มจำนวนบิตในตัวเลขให้มีค่ามาก (เช่น 1024 บิต) คุณสามารถกำหนดระยะเวลาที่อัลกอริธึมการแยกตัวประกอบเวลาเทียมเทียมต้องใช้เวลามากจนจะไม่สามารถแยกตัวประกอบได้อย่างสมบูรณ์และไม่เป็นไปได้ ตัวเลข ในทางกลับกันถ้าเราสามารถหาอัลกอริธึมการแยกตัวประกอบพหุนาม - เวลาได้ก็ไม่จำเป็นต้องเป็นเช่นนั้น การเพิ่มบิตมากขึ้นอาจทำให้งานเพิ่มขึ้นมาก แต่การเติบโตจะเป็นการเติบโตแบบพหุนามเท่านั้นไม่ใช่การเติบโตแบบเอ็กซ์โปเนนเชียล

ที่กล่าวว่าในหลาย ๆ กรณีอัลกอริธึมเวลาเทียมเทียมนั้นดีอย่างสมบูรณ์แบบเนื่องจากขนาดของตัวเลขจะไม่ใหญ่เกินไป ตัวอย่างเช่นการเรียงลำดับการนับมีรันไทม์ O (n + U) โดยที่ U คือจำนวนที่มากที่สุดในอาร์เรย์ นี่คือเวลา pseudopolynomial (เนื่องจากค่าตัวเลขของ U ต้องการบิต O (log U) ในการเขียนดังนั้นรันไทม์จึงเป็นเลขชี้กำลังในขนาดอินพุต) ถ้าเรา จำกัด U เพื่อไม่ให้ U มีขนาดใหญ่เกินไป (เช่นถ้าเราปล่อยให้ U เป็น 2) รันไทม์คือ O (n) ซึ่งจริงๆแล้วคือเวลาพหุนาม นี่คือวิธีการทำงานของการเรียงลำดับ radix : โดยการประมวลผลตัวเลขทีละบิตรันไทม์ของแต่ละรอบคือ O (n) ดังนั้นรันไทม์โดยรวมจึงเป็น O (n log U) นี่คือความจริง เวลาพหุนามเนื่องจากการเขียนตัวเลข n เพื่อเรียงลำดับจะใช้Ω (n) บิตและค่าของ log U เป็นสัดส่วนโดยตรงกับจำนวนบิตที่ต้องใช้ในการเขียนค่าสูงสุดในอาร์เรย์

หวังว่านี่จะช่วยได้!


27
นี่ควรเป็นคำอธิบายของ Wikipedia ...
Sandro Meier

4
เหตุใดisPrimeความซับซ้อนจึงประมาณเป็น O (n ^ 4) ไม่ใช่แค่ O (n) ฉันไม่เข้าใจ เว้นแต่ความซับซ้อนของn mod iจะเป็น O (n ^ 3) .... ซึ่งไม่แน่นอน
fons

4
@ ไม่มีใครปกติเราคิดค่าใช้จ่ายในการแก้ไขตัวเลขสองตัวเป็น O (1) แต่เมื่อคุณต้องจัดการกับตัวเลขจำนวนมากโดยพลการต้นทุนในการคูณจะเพิ่มขึ้นตามฟังก์ชันของขนาดของตัวเลขเอง เพื่อเป็นการอนุรักษ์นิยมอย่างยิ่งฉันอ้างว่าคุณสามารถคำนวณการปรับเปลี่ยนด้วยจำนวนที่น้อยกว่า n เป็น O (n ^ 3) ซึ่งเป็นการนับจำนวนที่มากเกินไป แต่ก็ยังไม่แย่เกินไป
templatetypedef

1
@AndrewFlemming มันขึ้นอยู่กับวิธีแสดงตัวเลขในหน่วยความจำ ฉันสมมติว่าเราใช้การแทนค่าฐานสองมาตรฐานโดยที่เราต้องการ log_2 n บิตเพื่อแสดงจำนวน คุณคิดถูกที่การเปลี่ยนการแสดงที่อยู่เบื้องหลังจะเปลี่ยนรันไทม์เป็นฟังก์ชันของขนาดของอินพุต
templatetypedef

1
การเลือก O (n ^ 3) สำหรับn mod iเป็นการอนุรักษ์นิยมมากเกินไป เวลาของmodเป็นฟังก์ชันของจำนวนบิตในnไม่ใช่nตัวเองดังนั้นจึงควรเป็น O ((log n) ^ 3)
dasblinkenlight

2

ความซับซ้อนของเวลาพหุนามหลอกหมายถึงพหุนามในค่า / ขนาดของอินพุต แต่เป็นเลขชี้กำลังในขนาดของอินพุต

ตามขนาดเราหมายถึงจำนวนบิตที่ต้องใช้ในการเขียนอินพุต

จากรหัสหลอกของกระเป๋าเป้เราสามารถหาความซับซ้อนของเวลาเป็น O (nW) ได้

// Input:
// Values (stored in array v) 
// Weights (stored in array w)
// Number of distinct items (n) //
Knapsack capacity (W) 
for w from 0 to W 
    do   m[0, w] := 0 
end for  
for i from 1 to n do  
        for j from 0 to W do
               if j >= w[i] then 
                      m[i, j] := max(m[i-1, j], m[i-1, j-w[i]] + v[i]) 
              else 
                      m[i, j] := m[i-1, j]
              end if
       end for 
end for

ในที่นี้ W ไม่ใช่พหุนามในความยาวของอินพุตซึ่งเป็นสิ่งที่ทำให้เป็นพหุนามหลอก

ให้ s เป็นจำนวนบิตที่ต้องการแทน W

i.e. size of input= s =log(W) (log= log base 2)
-> 2^(s)=2^(log(W))
-> 2^(s)=W  (because  2^(log(x)) = x)

ตอนนี้running time of knapsack= O (nW) = O (n * 2 ^ s) ซึ่งไม่ใช่พหุนาม

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.