Quarantine
Sofia open - spring
Submission name: quarantine.cpp
Problem summary
Contacts between people are listed in arbitrary chronological order. Starting from the named patient, count all other people who may be linked to the patient by a chain of contacts and should therefore also be quarantined.
Input
Zero or more lines of two names describing contacts. The final line has only the patient’s name. There is no initial count.
Output
The number of other people in the patient’s connected component.
Constraints
At most 10,000 people; names are single words shorter than 32 characters.
Worked example
An independently prepared example for this explanation.
Input
Ada Ben Ben Cy Dan Eve Ada
Output
2
Solution analysis
- Assign an integer vertex ID to each name. Each contact becomes an undirected edge.
- The final one-name line identifies the starting vertex. Read lines, rather than assuming every record has two names.
- Run an iterative DFS from that vertex. Mark vertices when pushing them.
- Subtract one from the visited count because the patient is already in the clinic.
Why it works
Possible exposure passes along chains of contacts, exactly the vertices reachable in the undirected contact graph. DFS finds precisely that component.
Watch out. The input has no N or M header. Duplicate contact records must not cause double-counting. An unconnected patient gives 0.
Commented C++17 solution
An independently written complete program with standard headers.
#include<iostream>
#include<sstream>
#include<string>
#include<unordered_map>
#include<vector>
#include<stack>
using namespace std;
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
unordered_map<string,int>id;
vector<vector<int>>g;
auto getID=[&](const string&name){
auto it=id.find(name);
if(it!=id.end()){
return it->second;
}
int v=(int)g.size();
id[name]=v;
g.push_back({});
return v;
};
string line;
int start=-1;
while(getline(cin,line)){
istringstream in(line);
string a,b;
if(!(in>>a)){
continue;
}
int u=getID(a);
if(in>>b){
int v=getID(b);
g[u].push_back(v);
g[v].push_back(u);
}
else{
start=u;
break;
} // Final line: only the patient's name.
}
if(start==-1){
return 0;
}
vector<bool>seen(g.size());
stack<int>st;
st.push(start);
seen[start]=true;
int count=0;
while(!st.empty()){
int v=st.top();
st.pop();
++count;
for(int u:g[v]){
if(!seen[u]){
seen[u]=true;
st.push(u);
}
}
}
cout<<count-1<<'\n';
}