To handle shared constraints.
Let's say myapp uses foo and bar, which both use shared_thing. To solve this, we need to pick a single version of shared_thing that both foo and bar work with. If foo and bar have narrow-to-the-point-of-precise constraints like shared_thing 1.2.3+bug-fix, then it's very likely that no version of shared_thing makes both foo and bar happy. The end result is no solution.
To accommodate that, packages are strongly encouraged to semantically version themselves. Then, when you depend on a package, you use as wide a range as you can. If foo wants shared_thing ">=1.2.3 <2.0.0" and bar wants ">=1.3.0 <2.0.0" then the solver can pick, say, 1.5.3, and both are happy.