So, this really depends on the access patterns you anticipate. First, shared_ptr comes at a potentially large cost in a multi-threaded program. Incrementing and decrementing the reference counts will cause processor cache invalidation on other CPUs. This will cause those operations to be slightly more expensive, and it will cause a lot of cache thrashing if those objects are being accessed in any way from multiple threads because even read access to bytes near the reference count will result in a very costly main memory fetch after the reference count has been updated.
Now, one way you could mitigate this is to not use make_shared like you're told to. This will result in the reference count being allocated separately from the object. But that potentially moves the cache problem elsewhere.
The various kinds of pointer are about expressing ownership. Does the object really have shared ownership? Or is it more appropriate to think of the Network as a whole as owning the object? If it's the latter, it might make more sense to store bare pointers and simply have a few vector objects (one per type) in the Network that hold unique_ptrs to all of the graph elements.
Is the number of contacts per particle bounded at a reasonably small number? If so, it might make sense to use a fixed size array that stores a list of bare pointers to contacts and have a Network object that actually owns all of the objects.
I'm sure there are more considerations. And my primary focus here has been on performance rather than some abstract notion of the 'right' way to do things. Perhaps something other than performance is your primary goal. Though, if that's the case, why are you using C++ here?