bpy.ops.view3d.snap_selected_to_cursor(use_offset=False) works manually (by using mouse and keyboard) but not using bpy
as @lemon says the answer is override the context
import bpy
for area in bpy.context.screen.areas:
    if area.type == 'VIEW_3D':
        override = bpy.context.copy()
        override['area'] = area
        override['region'] = area.regions[4]
        bpy.ops.view3d.snap_selected_to_cursor( override, use_offset=False)