I think this will do what you want:
<?php
$sql = "
SELECT DISTINCT t.name as cat_name, um1.meta_value AS first_name, um2.meta_value AS last_name
FROM $wpdb->terms t
JOIN $wpdb->term_taxonomy tt ON (tt.term_id = t.term_id AND taxonomy = 'category')
JOIN $wpdb->term_relationships tr ON (tr.term_taxonomy_id = tt.term_taxonomy_id)
JOIN $wpdb->posts p ON p.ID = tr.object_id
JOIN $wpdb->usermeta um1 ON (um1.user_id = p.post_author AND um1.meta_key = 'first_name')
JOIN $wpdb->usermeta um2 ON (um2.user_id = p.post_author AND um2.meta_key = 'last_name')
WHERE p.post_type = 'post'
AND p.post_status IN ('publish','private')
AND p.post_date <= NOW()
ORDER BY cat_name, first_name, last_name
";
$rows = $wpdb->get_results($sql);
// Now output category name person1, person2, ...
$curr_cat = '';
foreach ($rows as $row) {
if ($row->cat_name != $curr_cat) {
if ($curr_cat !== '') echo "</p>\n</div>\n"; // Close previous div
echo '<div class="cat_div">'; // Start new div
$curr_cat = $row->cat_name;
echo "CAT NAME: $row->cat_name";
echo "<p>AUTHOR: ";
$sep = '';
}
echo "$sep$row->first_name $row->last_name";
$sep = ', ';
}
echo "</p>\n</div>\n"; // Close previous div
?>
Put this code in a template styled for your theme.